This is an automated email from the ASF dual-hosted git repository. asf-gitbox-commits pushed a commit to branch trunk in repository https://gitbox.apache.org/repos/asf/openoffice.git
commit dcfbcfcc0e65200ed7e642920dcdc93553b55d00 Author: Pedro Giffuni <[email protected]> AuthorDate: Wed Oct 21 10:48:21 2026 -0500 freebsd_aarch64: Complete C++-UNO bridge implementation for FreeBSD aarch64 Implement the gcc3 FreeBSD aarch64 C++-UNO bridge, mirroring the macOS aarch64 reference implementation with adaptations for the System V / AAPCS64 ABI (FreeBSD). - abi.cxx: Implement align_stack_offset (8-byte alignment) and stack_size (rounded to 8 bytes) matching AAPCS64. - call.s: Add callVirtualFunction and privateSnippetExecutor assembly trampolines for aarch64. Fix return value loading with correct sp+144 offsets, add Lpse_void label for void returns, and fix typelib_TypeClass enum values (VOID=0, CHAR=1, BYTE=2, etc.). - cpp2uno.cxx: Implement cpp2uno_call and cpp_vtable_call for converting incoming C++ ABI arguments to UNO format, and VtableFactory methods (mapBlockToVtable, getBlockSize, initializeBlock, addLocalFunctions, flushCode). - except.cxx: Implement exception handling (synthesiseRTTI, deleteException, raiseException, fillUnoException). - uno2cpp.cxx: Implement cpp_call for converting UNO args to C++ ABI arguments, INSERT_* macros for register/stack parameter packing, and callVirtualMethod wrapper around the assembly trampoline. --- .../source/cpp_uno/gcc3_freebsd_aarch64/abi.cxx | 170 +++++--- .../source/cpp_uno/gcc3_freebsd_aarch64/call.s | 65 +-- .../cpp_uno/gcc3_freebsd_aarch64/cpp2uno.cxx | 146 +++++-- .../source/cpp_uno/gcc3_freebsd_aarch64/except.cxx | 149 +++++++ .../cpp_uno/gcc3_freebsd_aarch64/uno2cpp.cxx | 446 ++++++++++++++++++++- 5 files changed, 856 insertions(+), 120 deletions(-) diff --git a/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/abi.cxx b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/abi.cxx index 71b8692f79..c119e4580b 100644 --- a/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/abi.cxx +++ b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/abi.cxx @@ -197,115 +197,159 @@ namespace aarch64 bool examine_argument( typelib_TypeDescriptionReference *pTypeRef, bool bInReturn, int &nUsedGPR, int &nUsedFPR ) { - // For returns, the hidden param rule uses >16 bytes for aggregates. - if ( pTypeRef->eTypeClass == typelib_TypeClass_STRUCT || pTypeRef->eTypeClass == typelib_TypeClass_EXCEPTION ) - { - return classifyAggregate( pTypeRef, nUsedGPR, nUsedFPR ); - } + nUsedGPR = 0; + nUsedFPR = 0; - // Scalars: floats -> FPR, others -> GPR switch ( pTypeRef->eTypeClass ) { + case typelib_TypeClass_VOID: + return true; + + case typelib_TypeClass_CHAR: + case typelib_TypeClass_BOOLEAN: + case typelib_TypeClass_BYTE: + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + case typelib_TypeClass_ENUM: + nUsedGPR = 1; + return true; + case typelib_TypeClass_FLOAT: - nUsedFPR = 1; nUsedGPR = 0; return true; case typelib_TypeClass_DOUBLE: - nUsedFPR = 1; nUsedGPR = 0; return true; + nUsedFPR = 1; + return true; + + // These UNO types are always handled by the bridge as a pointer/ + // reference (one GPR), never passed by value through this classifier. + case typelib_TypeClass_STRING: + case typelib_TypeClass_TYPE: + case typelib_TypeClass_ANY: + case typelib_TypeClass_TYPEDEF: + case typelib_TypeClass_SEQUENCE: + case typelib_TypeClass_INTERFACE: + nUsedGPR = 1; + return true; + + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + if ( bInReturn ) + return classifyAggregate( pTypeRef, nUsedGPR, nUsedFPR ); + nUsedGPR = 1; // generated UNO C++ bindings pass aggregates by const reference + return true; + default: - nUsedFPR = 0; nUsedGPR = 1; return true; + return false; } } bool return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef ) { - if ( pTypeRef->eTypeClass == typelib_TypeClass_STRUCT || pTypeRef->eTypeClass == typelib_TypeClass_EXCEPTION ) + switch ( pTypeRef->eTypeClass ) { - typelib_TypeDescription * pTypeDescr = 0; - TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef ); - bool ret = pTypeDescr->nSize > 16; - TYPELIB_DANGER_RELEASE( pTypeDescr ); - return ret; + case typelib_TypeClass_STRING: + case typelib_TypeClass_TYPE: + case typelib_TypeClass_ANY: + case typelib_TypeClass_TYPEDEF: + case typelib_TypeClass_UNION: + case typelib_TypeClass_ARRAY: + case typelib_TypeClass_SEQUENCE: + case typelib_TypeClass_INTERFACE: + // These are C++ wrapper objects, not pointer-sized scalar values. + // On FreeBSD aarch64 (System V), C++ class return values (non-POD + // with non-trivial copy constructor) are returned via x8 buffer. + return true; + default: + break; + } + + if ( pTypeRef->eTypeClass == typelib_TypeClass_STRUCT || + pTypeRef->eTypeClass == typelib_TypeClass_EXCEPTION ) + { + if ( isComplexAggregate( pTypeRef ) ) + return true; } - return false; // scalars and small aggregates return in registers + + int g, s; + // Returned in registers iff examine_argument() says it fits; + // otherwise the caller must pass an indirect-result buffer in x8. + return !examine_argument( pTypeRef, true, g, s ); } sal_uInt32 get_return_kind( typelib_TypeDescriptionReference *pTypeRef ) { - if ( pTypeRef->eTypeClass == typelib_TypeClass_FLOAT ) - return typelib_TypeClass_FLOAT; - - if ( pTypeRef->eTypeClass == typelib_TypeClass_DOUBLE ) - return typelib_TypeClass_DOUBLE; - if ( pTypeRef->eTypeClass == typelib_TypeClass_STRUCT || pTypeRef->eTypeClass == typelib_TypeClass_EXCEPTION ) { HfaKind kind = HFA_NONE; int count = 0; - - if ( collectHfa( pTypeRef, kind, count ) ) - { - if ( kind == HFA_FLOAT ) - return RETURN_KIND_HFA_FLOAT; - - if ( kind == HFA_DOUBLE ) - return RETURN_KIND_HFA_DOUBLE; - } + if ( collectHfa( pTypeRef, kind, count ) && count >= 1 && count <= 4 ) + return kind == HFA_FLOAT ? RETURN_KIND_HFA_FLOAT : RETURN_KIND_HFA_DOUBLE; } - return pTypeRef->eTypeClass; } void fill_struct( typelib_TypeDescriptionReference *pTypeRef, const sal_uInt64* pGPR, const double* pFPR, void *pStruct ) { - // For small aggregates, copy from GPR slots; for HFAs, copy from FPR slots. - if ( pTypeRef->eTypeClass == typelib_TypeClass_STRUCT || pTypeRef->eTypeClass == typelib_TypeClass_EXCEPTION ) + int nUsedGPR = 0; + int nUsedFPR = 0; + if ( !examine_argument( pTypeRef, true, nUsedGPR, nUsedFPR ) ) + { + return; + } + + if ( nUsedFPR > 0 ) { - int nGPR=0, nFPR=0; - if ( classifyAggregate( pTypeRef, nGPR, nFPR ) ) + // HFA: each member occupies one v register; the members are contiguous + // in the struct. Copy element-by-element to honour FLOAT (4-byte) vs + // DOUBLE (8-byte) element width. + HfaKind kind = HFA_NONE; + int count = 0; + collectHfa( pTypeRef, kind, count ); + if ( kind == HFA_FLOAT ) { - if ( nFPR > 0 ) - { - // HFA: copy elements from FPR slots. For FLOAT HFAs each element is - // 4 bytes but occupies an 8-byte saved slot; copy each float from the - // low 4 bytes of the corresponding double-sized slot. DOUBLE HFAs - // can be copied directly. - HfaKind kind = HFA_NONE; - int count = 0; - if ( collectHfa( pTypeRef, kind, count ) && kind == HFA_FLOAT ) - { - for ( int i = 0; i < nFPR; ++i ) - memcpy( - static_cast<char *>( pStruct ) + i * sizeof(float), - reinterpret_cast<const char *>( pFPR) + i * sizeof(double), - sizeof(float) ); - } - else - { - memcpy( pStruct, pFPR, nFPR * sizeof(double) ); - } - } - else - { - memcpy( pStruct, pGPR, nGPR * sizeof(sal_uInt64) ); - } + float *pDest = reinterpret_cast< float *>( pStruct ); + for ( int i = 0; i < nUsedFPR; ++i ) + pDest[i] = *reinterpret_cast< const float *>( pFPR + i ); + } + else // HFA_DOUBLE + { + double *pDest = reinterpret_cast< double *>( pStruct ); + for ( int i = 0; i < nUsedFPR; ++i ) + pDest[i] = pFPR[i]; } } + else + { + typelib_TypeDescription * pTypeDescr = 0; + TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef ); + memcpy( pStruct, pGPR, pTypeDescr->nSize ); + TYPELIB_DANGER_RELEASE( pTypeDescr ); + } } sal_uInt32 align_stack_offset( sal_uInt32 offset, typelib_TypeDescriptionReference *pTypeRef ) { - // AArch64 stack overflow area is packed; align to natural alignment of the type (8) + // On aarch64 System V ABI, the smallest stack slot is 8 bytes. + // Align to 8 bytes regardless of the type's natural alignment. const sal_uInt32 align = 8; return ( offset + align - 1 ) & ~( align - 1 ); } sal_uInt32 stack_size( typelib_TypeDescriptionReference *pTypeRef ) { - // For simple types and small aggregates, size is rounded to 8 typelib_TypeDescription * pTypeDescr = 0; TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef ); sal_uInt32 size = pTypeDescr->nSize; TYPELIB_DANGER_RELEASE( pTypeDescr ); + // In the System V AMD64 / AAPCS64 stack layout, the smallest slot that + // can be passed is 8 bytes (the natural stack slot size). Round up + // so that small types like BOOLEAN (1B), SHORT (2B), LONG (4B) each + // occupy a full 8-byte slot on the overflow stack, matching what the + // callee's ABI expects. return ( size + 7 ) & ~7u; } diff --git a/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/call.s b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/call.s index 8eb2c6449e..284eff1f09 100644 --- a/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/call.s +++ b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/call.s @@ -143,54 +143,67 @@ privateSnippetExecutor: b.eq Lpse_signed_byte cmp w0, #4 // typelib_TypeClass_SHORT b.eq Lpse_signed_short - cmp w0, #1 // typelib_TypeClass_VOID + cmp w0, #1 // typelib_TypeClass_CHAR + b.eq Lpse_unsigned_short + cmp w0, #5 // typelib_TypeClass_UNSIGNED_SHORT + b.eq Lpse_unsigned_short + cmp w0, #2 // typelib_TypeClass_BOOLEAN + b.eq Lpse_unsigned_byte + cmp w0, #6 // typelib_TypeClass_LONG + b.eq Lpse_word + cmp w0, #7 // typelib_TypeClass_UNSIGNED_LONG + b.eq Lpse_word + cmp w0, #0 // typelib_TypeClass_VOID b.eq Lpse_void + cmp w0, #15 // typelib_TypeClass_ENUM + b.eq Lpse_word - // integer / pointer return - ldr x0, [x6, #0] - ldr x1, [x6, #8] - ldr d0, [x6, #16] - ldr d1, [x6, #24] + // integer / pointer / <=16B aggregate + ldr x0, [sp, #144] + ldr x1, [sp, #152] + b Lpse_finish + +Lpse_void: + mov x0, #0 b Lpse_finish Lpse_hfa_float: - // HFA float: up to 4 floats in d0..d3 - ldr d0, [x6, #0] - ldr d1, [x6, #8] - ldr d2, [x6, #16] - ldr d3, [x6, #24] + ldr s0, [sp, #144] + ldr s1, [sp, #148] + ldr s2, [sp, #152] + ldr s3, [sp, #156] b Lpse_finish Lpse_hfa_double: - // HFA double: up to 4 doubles in d0..d3 - ldr d0, [x6, #0] - ldr d1, [x6, #8] - ldr d2, [x6, #16] - ldr d3, [x6, #24] + ldp d0, d1, [sp, #144] + ldp d2, d3, [sp, #160] b Lpse_finish Lpse_float: - // single float/double returned in d0 - ldr d0, [x6, #16] + ldr d0, [sp, #144] b Lpse_finish Lpse_signed_byte: - ldr x0, [x6, #0] + ldrsb w0, [sp, #144] + b Lpse_finish + +Lpse_unsigned_byte: + ldrb w0, [sp, #144] b Lpse_finish Lpse_signed_short: - ldr x0, [x6, #0] + ldrsh w0, [sp, #144] b Lpse_finish -Lpse_void: - mov x0, #0 +Lpse_unsigned_short: + ldrh w0, [sp, #144] b Lpse_finish +Lpse_word: + ldr w0, [sp, #144] Lpse_finish: - ldp x23, x24, [sp], #16 - ldp x21, x22, [sp], #16 - ldp x19, x20, [sp], #16 - ldp x29, x30, [sp], #16 + mov sp, x29 + ldp x29, x30, [sp], #176 ret .cfi_endproc diff --git a/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/cpp2uno.cxx b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/cpp2uno.cxx index c6204dadf7..c97b3c3998 100644 --- a/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/cpp2uno.cxx +++ b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/cpp2uno.cxx @@ -120,19 +120,9 @@ static typelib_TypeClass cpp2uno_call( int nUsedGPR = 0; int nUsedFPR = 0; + aarch64::examine_argument( rParam.pTypeRef, false, nUsedGPR, nUsedFPR ); if ( !rParam.bOut && bridges::cpp_uno::shared::isSimpleType( rParam.pTypeRef ) ) // value { - // A simple UNO type occupies exactly one register, GPR or FPR. - if ( rParam.pTypeRef->eTypeClass == typelib_TypeClass_FLOAT || - rParam.pTypeRef->eTypeClass == typelib_TypeClass_DOUBLE ) - { - nUsedFPR = 1; nUsedGPR = 0; - } - else - { - nUsedFPR = 0; nUsedGPR = 1; - } - OSL_ASSERT( ( nUsedFPR == 1 && nUsedGPR == 0 ) || ( nUsedFPR == 0 && nUsedGPR == 1 ) ); if ( nUsedFPR == 1 ) @@ -203,24 +193,13 @@ static typelib_TypeClass cpp2uno_call( // will be released at reconversion ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; } - - if ( pCppStack ) + else // direct way { - if ( pParamTypeDescr->eTypeClass == typelib_TypeClass_STRUCT || - pParamTypeDescr->eTypeClass == typelib_TypeClass_EXCEPTION ) - { - // struct in registers/stack: copy it to a temporary if - // it needs conversion - if ( bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ) ) - { - // already handled above - } - else - pUnoArgs[nPos] = pCppStack; - } - } - if ( pParamTypeDescr ) + // struct in registers/stack: copy it directly + pUnoArgs[nPos] = pCppStack; + // no longer needed TYPELIB_DANGER_RELEASE( pParamTypeDescr ); + } } } @@ -436,3 +415,116 @@ extern "C" sal_uInt32 cpp_vtable_call( return eRet; } + + +//================================================================================================== +extern "C" void privateSnippetExecutor( void ); + +const int codeSnippetSize = 40; + +unsigned char * codeSnippet( unsigned char * code, + sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset, + bool bHasHiddenParam ) SAL_THROW( () ) +{ + sal_uInt64 nOffsetAndIndex = ( static_cast<sal_uInt64>( nVtableOffset ) << 32 ) | static_cast<sal_uInt64>( nFunctionIndex ); + + if ( bHasHiddenParam ) + nOffsetAndIndex |= 0x80000000; + + sal_uInt32 * p = reinterpret_cast<sal_uInt32 *>( code ); + + p[0] = 0x58000000 | ( 6 << 5 ) | 16; + p[1] = 0x58000000 | ( 7 << 5 ) | 17; + p[2] = 0xD61F0000 | ( 17 << 5 ); + p[3] = 0xD503201F; // NOP + p[4] = 0xD503201F; // NOP + + *reinterpret_cast<sal_uInt64 *>( code + 24 ) = nOffsetAndIndex; + *reinterpret_cast<sal_uInt64 *>( code + 32 ) = reinterpret_cast<sal_uInt64>( privateSnippetExecutor ); + + return code + codeSnippetSize; +} + +//================================================================================================== +struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; + +bridges::cpp_uno::shared::VtableFactory::Slot * +bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) +{ + return static_cast< Slot * >(block) + 2; +} + +//================================================================================================== +sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize( + sal_Int32 slotCount) +{ + return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize; +} + +//================================================================================================== +bridges::cpp_uno::shared::VtableFactory::Slot * +bridges::cpp_uno::shared::VtableFactory::initializeBlock( + void * block, sal_Int32 slotCount) +{ + Slot * slots = mapBlockToVtable(block); + slots[-2].fn = 0; + slots[-1].fn = 0; + return slots + slotCount; +} + +//================================================================================================== + +unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions( + Slot ** slots, unsigned char * code, sal_PtrDiff writetoexecdiff, + typelib_InterfaceTypeDescription const * type, sal_Int32 nFunctionOffset, + sal_Int32 functionCount, sal_Int32 nVtableOffset ) +{ + (*slots) -= functionCount; + Slot * s = *slots; + for ( sal_Int32 nPos = 0; nPos < type->nMembers; ++nPos ) + { + typelib_TypeDescription * pTD = 0; + + TYPELIB_DANGER_GET( &pTD, type->ppMembers[ nPos ] ); + OSL_ASSERT( pTD ); + + if ( typelib_TypeClass_INTERFACE_ATTRIBUTE == pTD->eTypeClass ) + { + typelib_InterfaceAttributeTypeDescription *pAttrTD = + reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( pTD ); + + (s++)->fn = code + writetoexecdiff; + code = codeSnippet( code, nFunctionOffset++, nVtableOffset, + aarch64::return_in_hidden_param( pAttrTD->pAttributeTypeRef ) ); + + if ( ! pAttrTD->bReadOnly ) + { + (s++)->fn = code + writetoexecdiff; + code = codeSnippet( code, nFunctionOffset++, nVtableOffset, false ); + } + } + else if ( typelib_TypeClass_INTERFACE_METHOD == pTD->eTypeClass ) + { + typelib_InterfaceMethodTypeDescription *pMethodTD = + reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( pTD ); + + (s++)->fn = code + writetoexecdiff; + code = codeSnippet( code, nFunctionOffset++, nVtableOffset, + aarch64::return_in_hidden_param( pMethodTD->pReturnTypeRef ) ); + } + else + OSL_ASSERT( false ); + + TYPELIB_DANGER_RELEASE( pTD ); + } + return code; +} + +//================================================================================================== +void bridges::cpp_uno::shared::VtableFactory::flushCode( + unsigned char const * begin, unsigned char const * end ) +{ + __clear_cache( + const_cast<unsigned char *>(begin), + const_cast<unsigned char *>(end) ); +} diff --git a/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/except.cxx b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/except.cxx index e8caa2151c..6161e1958d 100644 --- a/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/except.cxx +++ b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/except.cxx @@ -250,4 +250,153 @@ type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr ) SAL_THR return p; } +//__________________________________________________________________________________________________ +type_info * RTTI::synthesiseRTTI( + OString const & rSymbolName, + typelib_CompoundTypeDescription * pTypeDescr ) SAL_THROW( () ) +{ + if (! rttiDonorsUsable()) + return 0; + + type_info * pBaseRtti = 0; + if (pTypeDescr->pBaseTypeDescription != 0) + { + pBaseRtti = getRTTI( + (typelib_CompoundTypeDescription *) pTypeDescr->pBaseTypeDescription ); + if (pBaseRtti == 0) + return 0; + } + + char * pName = strdup( rSymbolName.getStr() + 4 ); + if (pName == 0) + return 0; + sal_uIntPtr nName = reinterpret_cast< sal_uIntPtr >( pName ); + if (rttiIsNonUnique()) + nName |= NON_UNIQUE_RTTI_BIT; + + if (pBaseRtti != 0) + { + RttiSiClassLayout * p = static_cast< RttiSiClassLayout * >( + calloc( 1, sizeof (RttiSiClassLayout) ) ); + if (p == 0) { free( pName ); return 0; } + p->pVtable = siDonor()->pVtable; + p->nName = nName; + p->pBase = pBaseRtti; + return reinterpret_cast< type_info * >( p ); + } + + RttiClassLayout * p = static_cast< RttiClassLayout * >( + calloc( 1, sizeof (RttiClassLayout) ) ); + if (p == 0) { free( pName ); return 0; } + p->pVtable = classDonor()->pVtable; + p->nName = nName; + return reinterpret_cast< type_info * >( p ); +} + +//-------------------------------------------------------------------------------------------------- +static void deleteException( void * pExc ) +{ + typelib_TypeDescription * pTD = 0; + { + MutexGuard guard( exceptionMapsMutex() ); + ThrownTypes::iterator i = thrownTypes().find( pExc ); + if ( i != thrownTypes().end() ) + { + pTD = i->second; + thrownTypes().erase( i ); + } + } + if ( pTD ) + { + ::uno_destructData( pExc, pTD, cpp_release ); + ::typelib_typedescription_release( pTD ); + } +} + +//================================================================================================== +void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp ) +{ + void * pCppExc; + type_info * rtti; + OUString typeName( + *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName ) ); + + OUString message; + if ( pUnoExc->pData != 0 && + *reinterpret_cast< rtl_uString * const * >( pUnoExc->pData ) != 0 ) + { + message = *reinterpret_cast< OUString const * >( pUnoExc->pData ); + } + + { + typelib_TypeDescription * pTypeDescr = 0; + TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType ); + OSL_ASSERT( pTypeDescr ); + if (! pTypeDescr) + { + throw RuntimeException( + OUString( RTL_CONSTASCII_USTRINGPARAM("cannot get typedescription for type ") ) + + typeName + OUString( RTL_CONSTASCII_USTRINGPARAM(": ") ) + message, + Reference< XInterface >() ); + } + + pCppExc = __cxa_allocate_exception( pTypeDescr->nSize ); + ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp ); + + static RTTI rtti_data; + rtti = rtti_data.getRTTI( + (typelib_CompoundTypeDescription *) pTypeDescr ); + OSL_ENSURE( rtti, "### no rtti for throwing exception!" ); + if (! rtti) + { + ::uno_destructData( pCppExc, pTypeDescr, cpp_release ); + __cxa_free_exception( pCppExc ); + TYPELIB_DANGER_RELEASE( pTypeDescr ); + ::uno_any_destruct( pUnoExc, 0 ); + throw RuntimeException( + OUString( RTL_CONSTASCII_USTRINGPARAM("no rtti for type ") ) + + typeName + OUString( RTL_CONSTASCII_USTRINGPARAM(": ") ) + message, + Reference< XInterface >() ); + } + + { + MutexGuard guard( exceptionMapsMutex() ); + typelib_typedescription_acquire( pTypeDescr ); + thrownTypes()[pCppExc] = pTypeDescr; + } + TYPELIB_DANGER_RELEASE( pTypeDescr ); + ::uno_any_destruct( pUnoExc, 0 ); + } + + __cxa_throw( pCppExc, rtti, deleteException ); +} + +void fillUnoException( + std::type_info const & type, void * exception, uno_Any * pUnoExc, + uno_Mapping * pCpp2Uno ) +{ + typelib_TypeDescription * pExcTypeDescr = 0; + OUString unoName( toUNOname( type.name() ) ); + { + MutexGuard guard( exceptionMapsMutex() ); + observedRttis()[unoName] = const_cast<std::type_info *>( &type ); + } + typelib_typedescription_getByName( &pExcTypeDescr, unoName.pData ); + if ( pExcTypeDescr == 0 ) + { + RuntimeException aRE( + OUString( RTL_CONSTASCII_USTRINGPARAM("exception type not found: ") ) + unoName, + Reference< XInterface >() ); + Type const & rType = ::getCppuType( &aRE ); + uno_type_any_constructAndConvert( + pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno ); + } + else + { + uno_any_constructAndConvert( + pUnoExc, exception, pExcTypeDescr, pCpp2Uno ); + typelib_typedescription_release( pExcTypeDescr ); + } +} + } // namespace CPPU_CURRENT_NAMESPACE diff --git a/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/uno2cpp.cxx b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/uno2cpp.cxx index 24e2627918..8cb8c0d517 100644 --- a/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/uno2cpp.cxx +++ b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/uno2cpp.cxx @@ -162,12 +162,11 @@ static void callVirtualMethod(void * pThis, sal_uInt32 nVtableIndex, *reinterpret_cast<float *>( &fpReturn[0] ); break; case typelib_TypeClass_DOUBLE: - *reinterpret_cast<double *>( pRegisterReturn ) = - *reinterpret_cast<double *>( &fpReturn[0] ); + *reinterpret_cast<double *>( pRegisterReturn ) = fpReturn[0]; break; case typelib_TypeClass_STRUCT: case typelib_TypeClass_EXCEPTION: - aarch64::fill_struct( pReturnTypeRef, gpReturn, fpReturn, pRegisterReturn ); + aarch64::fill_struct( pReturnTypeRef, &gpReturn[0], &fpReturn[0], pRegisterReturn ); break; default: break; @@ -186,4 +185,443 @@ extern "C" void callVirtualFunction( unsigned char *pStack, sal_uInt32 nStackBytes, sal_uInt64 *pGPRReturn, double *pFPRReturn ); -// ... per-bridge wrappers are generated at build time; no further code required here. +// Macros for inserting values into registers. Stack arguments are handled +// separately with a byte cursor because the AAPCS packs them by size/alignment. +// pSV - pointer to the source +// nr - order of the value [will be increased if stored to register] +// pFPR, pGPR - pointer to the register arrays + +#define INSERT_FLOAT( pSV, nr, pFPR ) \ + if ( nr < aarch64::MAX_FPR_REGS ) \ + { \ + pFPR[nr] = 0; \ + *reinterpret_cast<float *>( pFPR + nr++ ) = *reinterpret_cast<const float *>( pSV ); \ + } + +#define INSERT_DOUBLE( pSV, nr, pFPR ) \ + if ( nr < aarch64::MAX_FPR_REGS ) \ + pFPR[nr++] = *reinterpret_cast<const double *>( pSV ); + +#define INSERT_INT64( pSV, nr, pGPR ) \ + if ( nr < aarch64::MAX_GPR_REGS ) \ + pGPR[nr++] = *reinterpret_cast<const sal_uInt64 *>( pSV ); + +#define INSERT_INT32( pSV, nr, pGPR ) \ + if ( nr < aarch64::MAX_GPR_REGS ) \ + pGPR[nr++] = *reinterpret_cast<const sal_uInt32 *>( pSV ); + +#define INSERT_SIGNED_INT32( pSV, nr, pGPR ) \ + if ( nr < aarch64::MAX_GPR_REGS ) \ + pGPR[nr++] = static_cast<sal_uInt64>( *reinterpret_cast<const sal_Int32 *>( pSV ) ); + +#define INSERT_INT16( pSV, nr, pGPR ) \ + if ( nr < aarch64::MAX_GPR_REGS ) \ + pGPR[nr++] = *reinterpret_cast<const sal_uInt16 *>( pSV ); + +#define INSERT_SIGNED_INT16( pSV, nr, pGPR ) \ + if ( nr < aarch64::MAX_GPR_REGS ) \ + pGPR[nr++] = static_cast<sal_uInt64>( *reinterpret_cast<const sal_Int16 *>( pSV ) ); + +#define INSERT_INT8( pSV, nr, pGPR ) \ + if ( nr < aarch64::MAX_GPR_REGS ) \ + pGPR[nr++] = *reinterpret_cast<const sal_uInt8 *>( pSV ); + +#define INSERT_SIGNED_INT8( pSV, nr, pGPR ) \ + if ( nr < aarch64::MAX_GPR_REGS ) \ + pGPR[nr++] = static_cast<sal_uInt64>( *reinterpret_cast<const sal_Int8 *>( pSV ) ); + +//================================================================================================== + +namespace { + +void appendCString(OUStringBuffer & buffer, char const * text) { + if (text != 0) { + buffer.append( + OStringToOUString(OString(text), RTL_TEXTENCODING_ISO_8859_1)); + } +} + +} + +static void cpp_call( + bridges::cpp_uno::shared::UnoInterfaceProxy * pThis, + bridges::cpp_uno::shared::VtableSlot aVtableSlot, + typelib_TypeDescriptionReference * pReturnTypeRef, + sal_Int32 nParams, typelib_MethodParameter * pParams, + void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc ) +{ + unsigned char *pStackStart = static_cast<unsigned char *>( + __builtin_alloca( (nParams + 3) * sizeof(sal_uInt64) ) ); + sal_uInt32 nStack = 0; + + sal_uInt64 pGPR[aarch64::MAX_GPR_REGS]; + sal_uInt32 nGPR = 0; + + double pFPR[aarch64::MAX_FPR_REGS]; + sal_uInt32 nFPR = 0; + + typelib_TypeDescription * pReturnTypeDescr = 0; + TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef ); + OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" ); + + void * pCppReturn = 0; + + // Indirect-result pointer. On AArch64 this is passed in the dedicated x8 + // register, NOT as the first general-purpose argument (unlike x86-64 SysV). + void * pIndirectReturn = 0; + + bool bSimpleReturn = true; + if ( pReturnTypeDescr ) + { + if ( aarch64::return_in_hidden_param( pReturnTypeRef ) ) + bSimpleReturn = false; + + if ( bSimpleReturn ) + pCppReturn = pUnoReturn; + else + { + pCppReturn = bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )? + __builtin_alloca( pReturnTypeDescr->nSize ) : pUnoReturn; + pIndirectReturn = pCppReturn; + } + } + + void * pAdjustedThisPtr = reinterpret_cast< void ** >( pThis->getCppI() ) + aVtableSlot.offset; + INSERT_INT64( &pAdjustedThisPtr, nGPR, pGPR ); + + void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams ); + sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams); + typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams)); + + sal_Int32 nTempIndizes = 0; + + for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) + { + const typelib_MethodParameter & rParam = pParams[nPos]; + typelib_TypeDescription * pParamTypeDescr = 0; + TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef ); + + if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr )) + { + uno_copyAndConvertData( pCppArgs[nPos] = alloca( 8 ), pUnoArgs[nPos], pParamTypeDescr, + pThis->getBridge()->getUno2Cpp() ); + bool onStack = false; + + switch (pParamTypeDescr->eTypeClass) + { + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + onStack = nGPR >= aarch64::MAX_GPR_REGS; + INSERT_INT64( pCppArgs[nPos], nGPR, pGPR ); + break; + case typelib_TypeClass_LONG: + onStack = nGPR >= aarch64::MAX_GPR_REGS; + INSERT_SIGNED_INT32( pCppArgs[nPos], nGPR, pGPR ); + break; + case typelib_TypeClass_UNSIGNED_LONG: + case typelib_TypeClass_ENUM: + onStack = nGPR >= aarch64::MAX_GPR_REGS; + INSERT_INT32( pCppArgs[nPos], nGPR, pGPR ); + break; + case typelib_TypeClass_SHORT: + onStack = nGPR >= aarch64::MAX_GPR_REGS; + INSERT_SIGNED_INT16( pCppArgs[nPos], nGPR, pGPR ); + break; + case typelib_TypeClass_CHAR: + case typelib_TypeClass_UNSIGNED_SHORT: + onStack = nGPR >= aarch64::MAX_GPR_REGS; + INSERT_INT16( pCppArgs[nPos], nGPR, pGPR ); + break; + case typelib_TypeClass_BYTE: + onStack = nGPR >= aarch64::MAX_GPR_REGS; + INSERT_SIGNED_INT8( pCppArgs[nPos], nGPR, pGPR ); + break; + case typelib_TypeClass_BOOLEAN: + onStack = nGPR >= aarch64::MAX_GPR_REGS; + INSERT_INT8( pCppArgs[nPos], nGPR, pGPR ); + break; + case typelib_TypeClass_FLOAT: + onStack = nFPR >= aarch64::MAX_FPR_REGS; + INSERT_FLOAT( pCppArgs[nPos], nFPR, pFPR ); + break; + case typelib_TypeClass_DOUBLE: + onStack = nFPR >= aarch64::MAX_FPR_REGS; + INSERT_DOUBLE( pCppArgs[nPos], nFPR, pFPR ); + break; + default: + break; + } + if ( onStack ) + { + nStack = aarch64::align_stack_offset( nStack, rParam.pTypeRef ); + sal_uInt32 size = aarch64::stack_size( rParam.pTypeRef ); + memcpy( pStackStart + nStack, pCppArgs[nPos], size ); + nStack += size; + } + + TYPELIB_DANGER_RELEASE( pParamTypeDescr ); + } + else + { + if (! rParam.bIn) + { + uno_constructData( + pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ), + pParamTypeDescr ); + pTempIndizes[nTempIndizes] = nPos; + ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; + } + else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr )) + { + uno_copyAndConvertData( + pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ), + pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() ); + + pTempIndizes[nTempIndizes] = nPos; + ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; + } + else + { + pCppArgs[nPos] = pUnoArgs[nPos]; + TYPELIB_DANGER_RELEASE( pParamTypeDescr ); + } + if ( nGPR < aarch64::MAX_GPR_REGS ) + { + INSERT_INT64( &(pCppArgs[nPos]), nGPR, pGPR ); + } + else + { + nStack = (nStack + sizeof(void *) - 1) & ~(sizeof(void *) - 1); + memcpy( pStackStart + nStack, &pCppArgs[nPos], sizeof(void *) ); + nStack += sizeof(void *); + } + } + } + + try + { + try { + callVirtualMethod( + pAdjustedThisPtr, aVtableSlot.index, + pCppReturn, pReturnTypeRef, bSimpleReturn, + pIndirectReturn, + pStackStart, nStack, + pGPR, nGPR, + pFPR, nFPR ); + } catch (Exception &) { + throw; + } catch (std::exception & e) { + OUStringBuffer buf; + buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("C++ code threw ")); + appendCString(buf, typeid(e).name()); + buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(": ")); + appendCString(buf, e.what()); + throw RuntimeException( + buf.makeStringAndClear(), Reference< XInterface >()); + } catch (...) { + throw RuntimeException( + OUString( + RTL_CONSTASCII_USTRINGPARAM( + "C++ code threw unknown exception")), + Reference< XInterface >()); + } + + *ppUnoExc = 0; + + for ( ; nTempIndizes--; ) + { + sal_Int32 nIndex = pTempIndizes[nTempIndizes]; + typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes]; + + if (pParams[nIndex].bIn) + { + if (pParams[nIndex].bOut) + { + uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); + uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr, + pThis->getBridge()->getCpp2Uno() ); + } + } + else + { + uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr, + pThis->getBridge()->getCpp2Uno() ); + } + uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release ); + + TYPELIB_DANGER_RELEASE( pParamTypeDescr ); + } + if (pCppReturn && pUnoReturn != pCppReturn) + { + uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr, + pThis->getBridge()->getCpp2Uno() ); + uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release ); + } + } + catch (Exception & e) + { + std::type_info * type = CPPU_CURRENT_NAMESPACE::__cxa_current_exception_type(); + CPPU_CURRENT_NAMESPACE::fillUnoException( + type ? *type : typeid(e), &e, *ppUnoExc, + pThis->getBridge()->getCpp2Uno() ); + + for ( ; nTempIndizes--; ) + { + sal_Int32 nIndex = pTempIndizes[nTempIndizes]; + uno_destructData( + pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], cpp_release ); + TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] ); + } + if (pReturnTypeDescr) + TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); + } + catch (...) + { + RuntimeException e( + OUString( RTL_CONSTASCII_USTRINGPARAM("C++ code threw unknown exception") ), + Reference< XInterface >() ); + uno_type_any_constructAndConvert( + *ppUnoExc, &e, ::getCppuType( &e ).getTypeLibType(), + pThis->getBridge()->getCpp2Uno() ); + for ( ; nTempIndizes--; ) + { + sal_Int32 nIndex = pTempIndizes[nTempIndizes]; + uno_destructData( + pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], cpp_release ); + TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] ); + } + if (pReturnTypeDescr) + TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); + } +} + +//================================================================================================== + +namespace bridges { namespace cpp_uno { namespace shared { + +void unoInterfaceProxyDispatch( + uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr, + void * pReturn, void * pArgs[], uno_Any ** ppException ) +{ + bridges::cpp_uno::shared::UnoInterfaceProxy * pThis + = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI); +#if OSL_DEBUG_LEVEL > 0 + typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr; +#endif + + switch (pMemberDescr->eTypeClass) + { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + { +#if OSL_DEBUG_LEVEL > 0 + sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition; + OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### member pos out of range!" ); +#endif + VtableSlot aVtableSlot( + getVtableSlot( + reinterpret_cast< + typelib_InterfaceAttributeTypeDescription const * >( + pMemberDescr))); + + if (pReturn) + { + cpp_call( + pThis, aVtableSlot, + ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef, + 0, 0, + pReturn, pArgs, ppException ); + } + else + { + typelib_MethodParameter aParam; + aParam.pTypeRef = + ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef; + aParam.bIn = sal_True; + aParam.bOut = sal_False; + + typelib_TypeDescriptionReference * pReturnTypeRef = 0; + OUString aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") ); + typelib_typedescriptionreference_new( + &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData ); + + aVtableSlot.index += 1; + cpp_call( + pThis, aVtableSlot, + pReturnTypeRef, + 1, &aParam, + pReturn, pArgs, ppException ); + + typelib_typedescriptionreference_release( pReturnTypeRef ); + } + + break; + } + case typelib_TypeClass_INTERFACE_METHOD: + { +#if OSL_DEBUG_LEVEL > 0 + sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition; + OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### member pos out of range!" ); +#endif + VtableSlot aVtableSlot( + getVtableSlot( + reinterpret_cast< + typelib_InterfaceMethodTypeDescription const * >( + pMemberDescr))); + + switch (aVtableSlot.index) + { + case 1: + (*pUnoI->acquire)( pUnoI ); + *ppException = 0; + break; + case 2: + (*pUnoI->release)( pUnoI ); + *ppException = 0; + break; + case 0: + { + typelib_TypeDescription * pTD = 0; + TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() ); + if (pTD) + { + uno_Interface * pInterface = 0; + (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)( + pThis->getBridge()->getUnoEnv(), + (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD ); + + if (pInterface) + { + ::uno_any_construct( + reinterpret_cast< uno_Any * >( pReturn ), + &pInterface, pTD, 0 ); + (*pInterface->release)( pInterface ); + TYPELIB_DANGER_RELEASE( pTD ); + *ppException = 0; + break; + } + TYPELIB_DANGER_RELEASE( pTD ); + } + } + default: + cpp_call( + pThis, aVtableSlot, + ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef, + ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams, + ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams, + pReturn, pArgs, ppException ); + } + break; + } + default: + { + ::com::sun::star::uno::RuntimeException aExc( + OUString( RTL_CONSTASCII_USTRINGPARAM("illegal member type description!") ), + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() ); + + Type const & rExcType = ::getCppuType( &aExc ); + ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 ); + } + } +} + +} } }
