diff options
Diffstat (limited to 'bridges/source/cpp_uno/shared')
-rw-r--r-- | bridges/source/cpp_uno/shared/bridge.cxx | 226 | ||||
-rw-r--r-- | bridges/source/cpp_uno/shared/component.cxx | 272 | ||||
-rw-r--r-- | bridges/source/cpp_uno/shared/component.hxx | 39 | ||||
-rw-r--r-- | bridges/source/cpp_uno/shared/cppinterfaceproxy.cxx | 205 | ||||
-rw-r--r-- | bridges/source/cpp_uno/shared/guardedarray.hxx | 52 | ||||
-rw-r--r-- | bridges/source/cpp_uno/shared/makefile.mk | 53 | ||||
-rw-r--r-- | bridges/source/cpp_uno/shared/types.cxx | 126 | ||||
-rw-r--r-- | bridges/source/cpp_uno/shared/unointerfaceproxy.cxx | 142 | ||||
-rw-r--r-- | bridges/source/cpp_uno/shared/vtablefactory.cxx | 382 | ||||
-rw-r--r-- | bridges/source/cpp_uno/shared/vtables.cxx | 154 |
10 files changed, 1651 insertions, 0 deletions
diff --git a/bridges/source/cpp_uno/shared/bridge.cxx b/bridges/source/cpp_uno/shared/bridge.cxx new file mode 100644 index 000000000000..731eab39cc7c --- /dev/null +++ b/bridges/source/cpp_uno/shared/bridge.cxx @@ -0,0 +1,226 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_bridges.hxx" + +#include "bridges/cpp_uno/shared/bridge.hxx" + +#include "component.hxx" + +#include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx" +#include "bridges/cpp_uno/shared/unointerfaceproxy.hxx" + +#include "com/sun/star/uno/XInterface.hpp" +#include "osl/diagnose.h" +#include "osl/interlck.h" +#include "rtl/ustring.h" +#include "sal/types.h" +#include "typelib/typedescription.h" +#include "uno/dispatcher.h" +#include "uno/environment.h" +#include "uno/mapping.h" + +namespace bridges { namespace cpp_uno { namespace shared { + +void freeMapping(uno_Mapping * pMapping) +{ + delete static_cast< Bridge::Mapping * >( pMapping )->pBridge; +} + +void acquireMapping(uno_Mapping * pMapping) +{ + static_cast< Bridge::Mapping * >( pMapping )->pBridge->acquire(); +} + +void releaseMapping(uno_Mapping * pMapping) +{ + static_cast< Bridge::Mapping * >( pMapping )->pBridge->release(); +} + +void cpp2unoMapping( + uno_Mapping * pMapping, void ** ppUnoI, void * pCppI, + typelib_InterfaceTypeDescription * pTypeDescr) +{ + OSL_ENSURE( ppUnoI && pTypeDescr, "### null ptr!" ); + if (*ppUnoI) + { + (*reinterpret_cast< uno_Interface * >( *ppUnoI )->release)( + reinterpret_cast< uno_Interface * >( *ppUnoI ) ); + *ppUnoI = 0; + } + if (pCppI) + { + Bridge * pBridge = static_cast< Bridge::Mapping * >( pMapping )->pBridge; + + // get object id of interface to be wrapped + rtl_uString * pOId = 0; + (*pBridge->pCppEnv->getObjectIdentifier)( + pBridge->pCppEnv, &pOId, pCppI ); + OSL_ASSERT( pOId ); + + // try to get any known interface from target environment + (*pBridge->pUnoEnv->getRegisteredInterface)( + pBridge->pUnoEnv, ppUnoI, pOId, pTypeDescr ); + + if (! *ppUnoI) // no existing interface, register new proxy interface + { + // try to publish a new proxy (refcount initially 1) + uno_Interface * pSurrogate + = bridges::cpp_uno::shared::UnoInterfaceProxy::create( + pBridge, + static_cast< ::com::sun::star::uno::XInterface * >( pCppI ), + pTypeDescr, pOId ); + + // proxy may be exchanged during registration + (*pBridge->pUnoEnv->registerProxyInterface)( + pBridge->pUnoEnv, reinterpret_cast< void ** >( &pSurrogate ), + freeUnoInterfaceProxy, pOId, + pTypeDescr ); + + *ppUnoI = pSurrogate; + } + ::rtl_uString_release( pOId ); + } +} + +void uno2cppMapping( + uno_Mapping * pMapping, void ** ppCppI, void * pUnoI, + typelib_InterfaceTypeDescription * pTypeDescr) +{ + OSL_ASSERT( ppCppI && pTypeDescr ); + if (*ppCppI) + { + static_cast< ::com::sun::star::uno::XInterface * >( *ppCppI )-> + release(); + *ppCppI = 0; + } + if (pUnoI) + { + Bridge * pBridge = static_cast< Bridge::Mapping * >( pMapping )->pBridge; + + // get object id of uno interface to be wrapped + rtl_uString * pOId = 0; + (*pBridge->pUnoEnv->getObjectIdentifier)( + pBridge->pUnoEnv, &pOId, pUnoI ); + OSL_ASSERT( pOId ); + + // try to get any known interface from target environment + (*pBridge->pCppEnv->getRegisteredInterface)( + pBridge->pCppEnv, ppCppI, pOId, pTypeDescr ); + + if (! *ppCppI) // no existing interface, register new proxy interface + { + // try to publish a new proxy (ref count initially 1) + com::sun::star::uno::XInterface * pProxy + = bridges::cpp_uno::shared::CppInterfaceProxy::create( + pBridge, static_cast< uno_Interface * >( pUnoI ), + pTypeDescr, pOId ); + + // proxy may be exchanged during registration + (*pBridge->pCppEnv->registerProxyInterface)( + pBridge->pCppEnv, reinterpret_cast< void ** >( &pProxy ), + freeCppInterfaceProxy, pOId, + pTypeDescr ); + + *ppCppI = pProxy; + } + ::rtl_uString_release( pOId ); + } +} + +uno_Mapping * Bridge::createMapping( + uno_ExtEnvironment * pCppEnv, uno_ExtEnvironment * pUnoEnv, + bool bExportCpp2Uno) SAL_THROW(()) +{ + Bridge * bridge = new Bridge(pCppEnv, pUnoEnv, bExportCpp2Uno); + return bExportCpp2Uno ? &bridge->aCpp2Uno : &bridge->aUno2Cpp; +} + +void Bridge::acquire() SAL_THROW(()) +{ + if (1 == osl_incrementInterlockedCount( &nRef )) + { + if (bExportCpp2Uno) + { + uno_Mapping * pMapping = &aCpp2Uno; + ::uno_registerMapping( + &pMapping, freeMapping, (uno_Environment *)pCppEnv, + (uno_Environment *)pUnoEnv, 0 ); + } + else + { + uno_Mapping * pMapping = &aUno2Cpp; + ::uno_registerMapping( + &pMapping, freeMapping, (uno_Environment *)pUnoEnv, + (uno_Environment *)pCppEnv, 0 ); + } + } +} + +void Bridge::release() SAL_THROW(()) +{ + if (! osl_decrementInterlockedCount( &nRef )) + { + ::uno_revokeMapping( bExportCpp2Uno ? &aCpp2Uno : &aUno2Cpp ); + } +} + +Bridge::Bridge( + uno_ExtEnvironment * pCppEnv_, uno_ExtEnvironment * pUnoEnv_, + bool bExportCpp2Uno_) SAL_THROW(()) + : nRef( 1 ) + , pCppEnv( pCppEnv_ ) + , pUnoEnv( pUnoEnv_ ) + , bExportCpp2Uno( bExportCpp2Uno_ ) +{ + bridges::cpp_uno::shared::g_moduleCount.modCnt.acquire( + &bridges::cpp_uno::shared::g_moduleCount.modCnt ); + + aCpp2Uno.pBridge = this; + aCpp2Uno.acquire = acquireMapping; + aCpp2Uno.release = releaseMapping; + aCpp2Uno.mapInterface = cpp2unoMapping; + + aUno2Cpp.pBridge = this; + aUno2Cpp.acquire = acquireMapping; + aUno2Cpp.release = releaseMapping; + aUno2Cpp.mapInterface = uno2cppMapping; + + (*((uno_Environment *)pCppEnv)->acquire)( (uno_Environment *)pCppEnv ); + (*((uno_Environment *)pUnoEnv)->acquire)( (uno_Environment *)pUnoEnv ); +} + +Bridge::~Bridge() SAL_THROW(()) +{ + (*((uno_Environment *)pUnoEnv)->release)( (uno_Environment *)pUnoEnv ); + (*((uno_Environment *)pCppEnv)->release)( (uno_Environment *)pCppEnv ); + bridges::cpp_uno::shared::g_moduleCount.modCnt.release( + &bridges::cpp_uno::shared::g_moduleCount.modCnt ); +} + +} } } diff --git a/bridges/source/cpp_uno/shared/component.cxx b/bridges/source/cpp_uno/shared/component.cxx new file mode 100644 index 000000000000..1f8a6eccb41f --- /dev/null +++ b/bridges/source/cpp_uno/shared/component.cxx @@ -0,0 +1,272 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_bridges.hxx" + +#include "component.hxx" + +#include "bridges/cpp_uno/shared/bridge.hxx" + +#include "com/sun/star/uno/Reference.hxx" +#include "com/sun/star/uno/RuntimeException.hpp" +#include "com/sun/star/uno/XInterface.hpp" +#include "osl/diagnose.h" +#include "osl/mutex.hxx" +#include "osl/time.h" +#include "rtl/process.h" +#include "rtl/unload.h" +#include "rtl/ustrbuf.hxx" +#include "rtl/ustring.h" +#include "rtl/ustring.hxx" +#include "sal/types.h" +#include "uno/environment.h" +#include "uno/lbnames.h" +#include "uno/mapping.h" +#include "cppu/EnvDcp.hxx" + +namespace bridges { namespace cpp_uno { namespace shared { + +rtl_StandardModuleCount g_moduleCount = MODULE_COUNT_INIT; + +} } } + +namespace { + +#if (defined(__SUNPRO_CC) && (__SUNPRO_CC == 0x500)) \ + || (defined(__GNUC__) && defined(__APPLE__)) +static ::rtl::OUString * s_pStaticOidPart = 0; +#endif + +const ::rtl::OUString & SAL_CALL cppu_cppenv_getStaticOIdPart() SAL_THROW( () ) +{ +#if ! ((defined(__SUNPRO_CC) && (__SUNPRO_CC == 0x500)) \ + || (defined(__GNUC__) && defined(__APPLE__))) + static ::rtl::OUString * s_pStaticOidPart = 0; +#endif + if (! s_pStaticOidPart) + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + if (! s_pStaticOidPart) + { + ::rtl::OUStringBuffer aRet( 64 ); + aRet.appendAscii( RTL_CONSTASCII_STRINGPARAM("];") ); + // good guid + sal_uInt8 ar[16]; + ::rtl_getGlobalProcessId( ar ); + for ( sal_Int32 i = 0; i < 16; ++i ) + { + aRet.append( (sal_Int32)ar[i], 16 ); + } +#if (defined(__SUNPRO_CC) && (__SUNPRO_CC == 0x500)) \ + || (defined(__GNUC__) && defined(__APPLE__)) + s_pStaticOidPart = new ::rtl::OUString( aRet.makeStringAndClear() ); +#else + static ::rtl::OUString s_aStaticOidPart( + aRet.makeStringAndClear() ); + s_pStaticOidPart = &s_aStaticOidPart; +#endif + } + } + return *s_pStaticOidPart; +} + +} + +extern "C" { + +static void s_stub_computeObjectIdentifier(va_list * pParam) + SAL_THROW( () ) +{ + uno_ExtEnvironment * pEnv = va_arg(*pParam, uno_ExtEnvironment *); + rtl_uString ** ppOId = va_arg(*pParam, rtl_uString **); + void * pInterface = va_arg(*pParam, void *); + + + OSL_ENSURE( pEnv && ppOId && pInterface, "### null ptr!" ); + if (pEnv && ppOId && pInterface) + { + if (*ppOId) + { + rtl_uString_release( *ppOId ); + *ppOId = 0; + } + + try + { + ::com::sun::star::uno::Reference< + ::com::sun::star::uno::XInterface > xHome( + reinterpret_cast< ::com::sun::star::uno::XInterface * >( + pInterface ), + ::com::sun::star::uno::UNO_QUERY ); + OSL_ENSURE( xHome.is(), "### query to XInterface failed!" ); + if (xHome.is()) + { + // interface + ::rtl::OUStringBuffer oid( 64 ); + oid.append( reinterpret_cast< sal_Int64 >(xHome.get()), 16 ); + oid.append( (sal_Unicode)';' ); + // ;environment[context] + oid.append( + *reinterpret_cast< ::rtl::OUString const * >( + &((uno_Environment *) pEnv)->pTypeName ) ); + oid.append( (sal_Unicode)'[' ); + oid.append( + reinterpret_cast< sal_Int64 >( + ((uno_Environment *)pEnv)->pContext), + 16 ); + // ];good guid + oid.append( cppu_cppenv_getStaticOIdPart() ); + ::rtl::OUString aRet( oid.makeStringAndClear() ); + ::rtl_uString_acquire( *ppOId = aRet.pData ); + } + } + catch (::com::sun::star::uno::RuntimeException &) + { + OSL_ENSURE( + 0, "### RuntimeException occured udring queryInterface()!" ); + } + } +} + +static void SAL_CALL computeObjectIdentifier( + uno_ExtEnvironment * pExtEnv, rtl_uString ** ppOId, void * pInterface ) + SAL_THROW( () ) +{ + uno_Environment_invoke(&pExtEnv->aBase, s_stub_computeObjectIdentifier, pExtEnv, ppOId, pInterface); +} + +static void s_stub_acquireInterface(va_list * pParam) + SAL_THROW( () ) +{ + /*uno_ExtEnvironment * pExtEnv = */va_arg(*pParam, uno_ExtEnvironment *); + void * pCppI = va_arg(*pParam, void *); + + reinterpret_cast< ::com::sun::star::uno::XInterface * >( pCppI )->acquire(); +} + +static void SAL_CALL acquireInterface( uno_ExtEnvironment * pExtEnv, void * pCppI ) + SAL_THROW( () ) +{ + uno_Environment_invoke(&pExtEnv->aBase, s_stub_acquireInterface, pExtEnv, pCppI); +} + +static void s_stub_releaseInterface(va_list * pParam) + SAL_THROW( () ) +{ + /*uno_ExtEnvironment * pExtEnv = */va_arg(*pParam, uno_ExtEnvironment *); + void * pCppI = va_arg(*pParam, void *); + + reinterpret_cast< ::com::sun::star::uno::XInterface * >( pCppI )->release(); +} + +static void SAL_CALL releaseInterface( uno_ExtEnvironment * pExtEnv, void * pCppI ) + SAL_THROW( () ) +{ + uno_Environment_invoke(&pExtEnv->aBase, s_stub_releaseInterface, pExtEnv, pCppI); +} + +static void SAL_CALL environmentDisposing( uno_Environment * ) SAL_THROW( () ) +{ + bridges::cpp_uno::shared::g_moduleCount.modCnt.release( + &bridges::cpp_uno::shared::g_moduleCount.modCnt ); +} + +sal_Bool SAL_CALL component_canUnload(TimeValue * pTime) SAL_THROW_EXTERN_C() { + return bridges::cpp_uno::shared::g_moduleCount.canUnload( + &bridges::cpp_uno::shared::g_moduleCount, pTime); +} + +void SAL_CALL uno_initEnvironment(uno_Environment * pCppEnv) + SAL_THROW_EXTERN_C() +{ + OSL_ENSURE( pCppEnv->pExtEnv, "### expected extended environment!" ); + OSL_ENSURE( + ::rtl_ustr_ascii_compare_WithLength( + pCppEnv->pTypeName->buffer, rtl_str_getLength(CPPU_CURRENT_LANGUAGE_BINDING_NAME), CPPU_CURRENT_LANGUAGE_BINDING_NAME ) + == 0, + "### wrong environment type!" ); + bridges::cpp_uno::shared::g_moduleCount.modCnt.acquire( + &bridges::cpp_uno::shared::g_moduleCount.modCnt ); + ((uno_ExtEnvironment *)pCppEnv)->computeObjectIdentifier + = computeObjectIdentifier; + ((uno_ExtEnvironment *)pCppEnv)->acquireInterface = acquireInterface; + ((uno_ExtEnvironment *)pCppEnv)->releaseInterface = releaseInterface; + pCppEnv->environmentDisposing = environmentDisposing; +} + +void SAL_CALL uno_ext_getMapping( + uno_Mapping ** ppMapping, uno_Environment * pFrom, uno_Environment * pTo) + SAL_THROW_EXTERN_C() +{ + OSL_ASSERT( ppMapping && pFrom && pTo ); + if (ppMapping && pFrom && pTo && pFrom->pExtEnv && pTo->pExtEnv) + { + uno_Mapping * pMapping = 0; + + rtl::OUString from_envTypeName(cppu::EnvDcp::getTypeName(pFrom->pTypeName)); + rtl::OUString to_envTypeName(cppu::EnvDcp::getTypeName(pTo->pTypeName)); + + if (0 == rtl_ustr_ascii_compare( + from_envTypeName.pData->buffer, + CPPU_CURRENT_LANGUAGE_BINDING_NAME ) && + 0 == rtl_ustr_ascii_compare( + to_envTypeName.pData->buffer, UNO_LB_UNO )) + { + // ref count initially 1 + pMapping = bridges::cpp_uno::shared::Bridge::createMapping( + pFrom->pExtEnv, pTo->pExtEnv, sal_True ); + ::uno_registerMapping( + &pMapping, bridges::cpp_uno::shared::freeMapping, + (uno_Environment *)pFrom->pExtEnv, + (uno_Environment *)pTo->pExtEnv, 0 ); + } + else if (0 == rtl_ustr_ascii_compare( + to_envTypeName.pData->buffer, + CPPU_CURRENT_LANGUAGE_BINDING_NAME ) && + 0 == rtl_ustr_ascii_compare( + from_envTypeName.pData->buffer, UNO_LB_UNO )) + { + // ref count initially 1 + pMapping = bridges::cpp_uno::shared::Bridge::createMapping( + pTo->pExtEnv, pFrom->pExtEnv, sal_False ); + ::uno_registerMapping( + &pMapping, bridges::cpp_uno::shared::freeMapping, + (uno_Environment *)pFrom->pExtEnv, + (uno_Environment *)pTo->pExtEnv, 0 ); + } + + if (*ppMapping) + { + (*(*ppMapping)->release)( *ppMapping ); + } + if (pMapping) + *ppMapping = pMapping; + } +} + +} diff --git a/bridges/source/cpp_uno/shared/component.hxx b/bridges/source/cpp_uno/shared/component.hxx new file mode 100644 index 000000000000..31622f312304 --- /dev/null +++ b/bridges/source/cpp_uno/shared/component.hxx @@ -0,0 +1,39 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_BRIDGES_SOURCE_CPP_UNO_SHARED_COMPONENT_HXX +#define INCLUDED_BRIDGES_SOURCE_CPP_UNO_SHARED_COMPONENT_HXX + +#include "rtl/unload.h" + +namespace bridges { namespace cpp_uno { namespace shared { + +extern rtl_StandardModuleCount g_moduleCount; + +} } } + +#endif diff --git a/bridges/source/cpp_uno/shared/cppinterfaceproxy.cxx b/bridges/source/cpp_uno/shared/cppinterfaceproxy.cxx new file mode 100644 index 000000000000..90c53d258d10 --- /dev/null +++ b/bridges/source/cpp_uno/shared/cppinterfaceproxy.cxx @@ -0,0 +1,205 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_bridges.hxx" + +#include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx" + +#include "guardedarray.hxx" + +#include "bridges/cpp_uno/shared/bridge.hxx" +#include "bridges/cpp_uno/shared/vtablefactory.hxx" + +#include "com/sun/star/uno/XInterface.hpp" +#include "osl/diagnose.h" +#include "osl/getglobalmutex.hxx" +#include "osl/interlck.h" +#include "osl/mutex.hxx" +#include "rtl/instance.hxx" +#include "typelib/typedescription.h" + +#include <cstddef> +#include <new> + + +static bridges::cpp_uno::shared::VtableFactory * pInstance; + +#if defined(__GNUG__) && !defined(__MINGW32__) +void dso_init(void) __attribute__((constructor)); +void dso_exit(void) __attribute__((destructor)); +#endif + +void dso_init(void) { + if (!pInstance) + pInstance = new bridges::cpp_uno::shared::VtableFactory(); +} + +void dso_exit(void) { + if (pInstance) + { + delete pInstance; + pInstance = NULL; + } +} + +#ifdef __SUNPRO_CC +# pragma init(dso_init) +# pragma fini(dso_exit) +#endif + + + +namespace { + +struct InitVtableFactory { + bridges::cpp_uno::shared::VtableFactory * operator()() { + return pInstance; + } +}; + +bridges::cpp_uno::shared::VtableFactory * getVtableFactory() { + return rtl_Instance< + bridges::cpp_uno::shared::VtableFactory, InitVtableFactory, + osl::MutexGuard, osl::GetGlobalMutex >::create( + InitVtableFactory(), osl::GetGlobalMutex()); +} + +} + +namespace bridges { namespace cpp_uno { namespace shared { + +void freeCppInterfaceProxy(uno_ExtEnvironment * pEnv, void * pInterface) +{ + CppInterfaceProxy * pThis = CppInterfaceProxy::castInterfaceToProxy( + pInterface); + if (pEnv != pThis->pBridge->getCppEnv()) { + OSL_ASSERT(false); + } + + (*pThis->pBridge->getUnoEnv()->revokeInterface)( + pThis->pBridge->getUnoEnv(), pThis->pUnoI ); + (*pThis->pUnoI->release)( pThis->pUnoI ); + ::typelib_typedescription_release( + (typelib_TypeDescription *)pThis->pTypeDescr ); + pThis->pBridge->release(); + +#if OSL_DEBUG_LEVEL > 1 + *(int *)pInterface = 0xdeadbabe; +#endif + pThis->~CppInterfaceProxy(); + delete[] reinterpret_cast< char * >(pThis); +} + +com::sun::star::uno::XInterface * CppInterfaceProxy::create( + bridges::cpp_uno::shared::Bridge * pBridge, uno_Interface * pUnoI, + typelib_InterfaceTypeDescription * pTypeDescr, rtl::OUString const & rOId) + SAL_THROW(()) +{ + typelib_typedescription_complete( + reinterpret_cast< typelib_TypeDescription ** >(&pTypeDescr)); + bridges::cpp_uno::shared::VtableFactory::Vtables aVtables( + getVtableFactory()->getVtables(pTypeDescr)); + bridges::cpp_uno::shared::GuardedArray< char > pMemory( + new char[ + sizeof (CppInterfaceProxy) + + (aVtables.count - 1) * sizeof (void **)]); + new(pMemory.get()) CppInterfaceProxy(pBridge, pUnoI, pTypeDescr, rOId); + CppInterfaceProxy * pProxy = reinterpret_cast< CppInterfaceProxy * >( + pMemory.release()); + for (sal_Int32 i = 0; i < aVtables.count; ++i) { + pProxy->vtables[i] = VtableFactory::mapBlockToVtable( + aVtables.blocks[i].start); + } + return castProxyToInterface(pProxy); +} + +void CppInterfaceProxy::acquireProxy() SAL_THROW(()) +{ + if (1 == osl_incrementInterlockedCount( &nRef )) + { + // rebirth of proxy zombie + // register at cpp env + void * pThis = castProxyToInterface( this ); + (*pBridge->getCppEnv()->registerProxyInterface)( + pBridge->getCppEnv(), &pThis, freeCppInterfaceProxy, oid.pData, + pTypeDescr ); + OSL_ASSERT( pThis == castProxyToInterface( this ) ); + } +} + +void CppInterfaceProxy::releaseProxy() SAL_THROW(()) +{ + if (! osl_decrementInterlockedCount( &nRef )) // last release + { + // revoke from cpp env + (*pBridge->getCppEnv()->revokeInterface)( + pBridge->getCppEnv(), castProxyToInterface( this ) ); + } +} + +CppInterfaceProxy::CppInterfaceProxy( + bridges::cpp_uno::shared::Bridge * pBridge_, uno_Interface * pUnoI_, + typelib_InterfaceTypeDescription * pTypeDescr_, rtl::OUString const & rOId_) + SAL_THROW(()) + : nRef( 1 ) + , pBridge( pBridge_ ) + , pUnoI( pUnoI_ ) + , pTypeDescr( pTypeDescr_ ) + , oid( rOId_ ) +{ + pBridge->acquire(); + ::typelib_typedescription_acquire( (typelib_TypeDescription *)pTypeDescr ); + (*pUnoI->acquire)( pUnoI ); + (*pBridge->getUnoEnv()->registerInterface)( + pBridge->getUnoEnv(), reinterpret_cast< void ** >( &pUnoI ), oid.pData, + pTypeDescr ); +} + +CppInterfaceProxy::~CppInterfaceProxy() +{} + +com::sun::star::uno::XInterface * CppInterfaceProxy::castProxyToInterface( + CppInterfaceProxy * pProxy) +{ + return reinterpret_cast< com::sun::star::uno::XInterface * >( + &pProxy->vtables); +} + +CppInterfaceProxy * CppInterfaceProxy::castInterfaceToProxy(void * pInterface) +{ + // pInterface == &pProxy->vtables (this emulated offsetof is not truly + // portable): + char const * const base = reinterpret_cast< char const * >(16); + std::ptrdiff_t const offset = reinterpret_cast< char const * >( + &reinterpret_cast< CppInterfaceProxy const * >(base)->vtables) - base; + return reinterpret_cast< CppInterfaceProxy * >( + static_cast< char * >(pInterface) - offset); +} + +} } } diff --git a/bridges/source/cpp_uno/shared/guardedarray.hxx b/bridges/source/cpp_uno/shared/guardedarray.hxx new file mode 100644 index 000000000000..b49def85ac64 --- /dev/null +++ b/bridges/source/cpp_uno/shared/guardedarray.hxx @@ -0,0 +1,52 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef INCLUDED_BRIDGES_SOURCE_CPP_UNO_SHARED_GUARDEDARRAY_HXX +#define INCLUDED_BRIDGES_SOURCE_CPP_UNO_SHARED_GUARDEDARRAY_HXX + +namespace bridges { namespace cpp_uno { namespace shared { + +template< typename T > class GuardedArray { +public: + explicit GuardedArray(T * thePointer): pointer(thePointer) {} + + ~GuardedArray() { delete[] pointer; } + + T * get() const { return pointer; } + + T * release() { T * p = pointer; pointer = 0; return p; } + +private: + GuardedArray(GuardedArray &); // not implemented + void operator =(GuardedArray); // not implemented + + T * pointer; +}; + +} } } + +#endif diff --git a/bridges/source/cpp_uno/shared/makefile.mk b/bridges/source/cpp_uno/shared/makefile.mk new file mode 100644 index 000000000000..4ce8122f3261 --- /dev/null +++ b/bridges/source/cpp_uno/shared/makefile.mk @@ -0,0 +1,53 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ = ..$/..$/.. +PRJNAME = bridges + +TARGET = cpp_uno_shared +ENABLE_EXCEPTIONS = TRUE + +.INCLUDE: settings.mk + +SLOFILES = \ + $(SLO)$/bridge.obj \ + $(SLO)$/component.obj \ + $(SLO)$/cppinterfaceproxy.obj \ + $(SLO)$/types.obj \ + $(SLO)$/unointerfaceproxy.obj \ + $(SLO)$/vtablefactory.obj \ + $(SLO)$/vtables.obj + +# Disable optimization for cppinterfaceproxy.cxx - +# attribute constructor / destructor do not get called otherwise. +.IF "$(COM)" == "GCC" +NOOPTFILES = \ + $(SLO)$/cppinterfaceproxy.obj +.ENDIF + + +.INCLUDE: target.mk diff --git a/bridges/source/cpp_uno/shared/types.cxx b/bridges/source/cpp_uno/shared/types.cxx new file mode 100644 index 000000000000..6a08038f9902 --- /dev/null +++ b/bridges/source/cpp_uno/shared/types.cxx @@ -0,0 +1,126 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_bridges.hxx" + +#include "bridges/cpp_uno/shared/types.hxx" +#define INCLUDED_BRIDGES_CPP_UNO_SHARED_VTABLES_HXX + +#include "typelib/typeclass.h" +#include "typelib/typedescription.h" + +namespace bridges { namespace cpp_uno { namespace shared { + +bool isSimpleType(typelib_TypeClass typeClass) { + return typeClass <= typelib_TypeClass_DOUBLE + || typeClass == typelib_TypeClass_ENUM; +} + +bool isSimpleType(typelib_TypeDescriptionReference const * type) { + return isSimpleType(type->eTypeClass); +} + +bool isSimpleType(typelib_TypeDescription const * type) { + return isSimpleType(type->eTypeClass); +} + +bool relatesToInterfaceType(typelib_TypeDescription const * type) { + switch (type->eTypeClass) { + case typelib_TypeClass_ANY: + case typelib_TypeClass_INTERFACE: + return true; + + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + typelib_CompoundTypeDescription const * p + = reinterpret_cast< typelib_CompoundTypeDescription const * >( + type); + for (sal_Int32 i = 0; i < p->nMembers; ++i) { + switch (p->ppTypeRefs[i]->eTypeClass) { + case typelib_TypeClass_ANY: + case typelib_TypeClass_INTERFACE: + return true; + + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + case typelib_TypeClass_SEQUENCE: + { + typelib_TypeDescription * t = 0; + TYPELIB_DANGER_GET(&t, p->ppTypeRefs[i]); + bool b = relatesToInterfaceType(t); + TYPELIB_DANGER_RELEASE(t); + if (b) { + return true; + } + } + break; + + default: + break; + } + } + if (p->pBaseTypeDescription != 0) { + return relatesToInterfaceType(&p->pBaseTypeDescription->aBase); + } + } + break; + + case typelib_TypeClass_SEQUENCE: + switch (reinterpret_cast< typelib_IndirectTypeDescription const * >( + type)->pType->eTypeClass) { + case typelib_TypeClass_ANY: + case typelib_TypeClass_INTERFACE: + return true; + + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + case typelib_TypeClass_SEQUENCE: + { + typelib_TypeDescription * t = 0; + TYPELIB_DANGER_GET( + &t, + reinterpret_cast< typelib_IndirectTypeDescription const * >( + type)->pType); + bool b = relatesToInterfaceType(t); + TYPELIB_DANGER_RELEASE(t); + return b; + } + + default: + break; + } + break; + + default: + break; + } + return false; +} + +} } } diff --git a/bridges/source/cpp_uno/shared/unointerfaceproxy.cxx b/bridges/source/cpp_uno/shared/unointerfaceproxy.cxx new file mode 100644 index 000000000000..1f5580eb2f30 --- /dev/null +++ b/bridges/source/cpp_uno/shared/unointerfaceproxy.cxx @@ -0,0 +1,142 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_bridges.hxx" + +#include "bridges/cpp_uno/shared/unointerfaceproxy.hxx" + +#include "bridges/cpp_uno/shared/bridge.hxx" + +#include "com/sun/star/uno/XInterface.hpp" +#include "osl/diagnose.h" +#include "osl/interlck.h" +#include "typelib/typedescription.h" +#include "uno/dispatcher.h" + +namespace bridges { namespace cpp_uno { namespace shared { + +void freeUnoInterfaceProxy(uno_ExtEnvironment * pEnv, void * pProxy) +{ + UnoInterfaceProxy * pThis = + static_cast< UnoInterfaceProxy * >( + reinterpret_cast< uno_Interface * >( pProxy ) ); + if (pEnv != pThis->pBridge->getUnoEnv()) { + OSL_ASSERT(false); + } + + (*pThis->pBridge->getCppEnv()->revokeInterface)( + pThis->pBridge->getCppEnv(), pThis->pCppI ); + pThis->pCppI->release(); + ::typelib_typedescription_release( + (typelib_TypeDescription *)pThis->pTypeDescr ); + pThis->pBridge->release(); + +#if OSL_DEBUG_LEVEL > 1 + *(int *)pProxy = 0xdeadbabe; +#endif + delete pThis; +} + +void acquireProxy(uno_Interface * pUnoI) +{ + if (1 == osl_incrementInterlockedCount( + & static_cast< UnoInterfaceProxy * >( pUnoI )->nRef )) + { + // rebirth of proxy zombie + // register at uno env +#if OSL_DEBUG_LEVEL > 1 + void * pThis = pUnoI; +#endif + (*static_cast< UnoInterfaceProxy * >( pUnoI )->pBridge->getUnoEnv()-> + registerProxyInterface)( + static_cast< UnoInterfaceProxy * >( pUnoI )->pBridge->getUnoEnv(), + reinterpret_cast< void ** >( &pUnoI ), freeUnoInterfaceProxy, + static_cast< UnoInterfaceProxy * >( pUnoI )->oid.pData, + static_cast< UnoInterfaceProxy * >( pUnoI )->pTypeDescr ); +#if OSL_DEBUG_LEVEL > 1 + OSL_ASSERT( pThis == pUnoI ); +#endif + } +} + +void releaseProxy(uno_Interface * pUnoI) +{ + if (! osl_decrementInterlockedCount( + & static_cast< UnoInterfaceProxy * >( pUnoI )->nRef )) + { + // revoke from uno env on last release + (*static_cast< UnoInterfaceProxy * >( pUnoI )->pBridge->getUnoEnv()-> + revokeInterface)( + static_cast< UnoInterfaceProxy * >( pUnoI )->pBridge->getUnoEnv(), + pUnoI ); + } +} + +UnoInterfaceProxy * UnoInterfaceProxy::create( + bridges::cpp_uno::shared::Bridge * pBridge, + com::sun::star::uno::XInterface * pCppI, + typelib_InterfaceTypeDescription * pTypeDescr, + rtl::OUString const & rOId) SAL_THROW(()) +{ + return new UnoInterfaceProxy(pBridge, pCppI, pTypeDescr, rOId); +} + +UnoInterfaceProxy::UnoInterfaceProxy( + bridges::cpp_uno::shared::Bridge * pBridge_, + com::sun::star::uno::XInterface * pCppI_, + typelib_InterfaceTypeDescription * pTypeDescr_, rtl::OUString const & rOId_) + SAL_THROW(()) + : nRef( 1 ) + , pBridge( pBridge_ ) + , pCppI( pCppI_ ) + , pTypeDescr( pTypeDescr_ ) + , oid( rOId_ ) +{ + pBridge->acquire(); + ::typelib_typedescription_acquire( (typelib_TypeDescription *)pTypeDescr ); + if (! ((typelib_TypeDescription *)pTypeDescr)->bComplete) + ::typelib_typedescription_complete( + (typelib_TypeDescription **)&pTypeDescr ); + OSL_ENSURE( + ((typelib_TypeDescription *)pTypeDescr)->bComplete, + "### type is incomplete!" ); + pCppI->acquire(); + (*pBridge->getCppEnv()->registerInterface)( + pBridge->getCppEnv(), reinterpret_cast< void ** >( &pCppI ), oid.pData, + pTypeDescr ); + + // uno_Interface + acquire = acquireProxy; + release = releaseProxy; + pDispatcher = unoInterfaceProxyDispatch; +} + +UnoInterfaceProxy::~UnoInterfaceProxy() +{} + +} } } diff --git a/bridges/source/cpp_uno/shared/vtablefactory.cxx b/bridges/source/cpp_uno/shared/vtablefactory.cxx new file mode 100644 index 000000000000..58c275a11234 --- /dev/null +++ b/bridges/source/cpp_uno/shared/vtablefactory.cxx @@ -0,0 +1,382 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_bridges.hxx" + +#if defined OS2 +#define INCL_DOS +#define INCL_DOSMISC +#endif + +#include "bridges/cpp_uno/shared/vtablefactory.hxx" + +#include "guardedarray.hxx" + +#include "bridges/cpp_uno/shared/vtables.hxx" + +#include "osl/thread.h" +#include "osl/security.hxx" +#include "osl/file.hxx" +#include "osl/diagnose.h" +#include "osl/mutex.hxx" +#include "rtl/alloc.h" +#include "rtl/ustring.hxx" +#include "sal/types.h" +#include "typelib/typedescription.hxx" + +#include <hash_map> +#include <new> +#include <vector> + +#if defined SAL_UNX +#include <unistd.h> +#include <string.h> +#include <sys/mman.h> +#elif defined SAL_W32 +#define WIN32_LEAN_AND_MEAN +#ifdef _MSC_VER +#pragma warning(push,1) // disable warnings within system headers +#endif +#include <windows.h> +#ifdef _MSC_VER +#pragma warning(pop) +#endif +#elif defined SAL_OS2 +#define INCL_DOS +#define INCL_DOSMISC +#include <os2.h> +#else +#error Unsupported platform +#endif + +using bridges::cpp_uno::shared::VtableFactory; + +namespace { + +extern "C" void * SAL_CALL allocExec(rtl_arena_type *, sal_Size * size) { + sal_Size pagesize; +#if defined SAL_UNX +#if defined FREEBSD || defined NETBSD + pagesize = getpagesize(); +#else + pagesize = sysconf(_SC_PAGESIZE); +#endif +#elif defined SAL_W32 + SYSTEM_INFO info; + GetSystemInfo(&info); + pagesize = info.dwPageSize; +#elif defined(SAL_OS2) + ULONG ulPageSize; + DosQuerySysInfo(QSV_PAGE_SIZE, QSV_PAGE_SIZE, &ulPageSize, sizeof(ULONG)); + pagesize = (sal_Size)ulPageSize; +#else +#error Unsupported platform +#endif + sal_Size n = (*size + (pagesize - 1)) & ~(pagesize - 1); + void * p; +#if defined SAL_UNX + p = mmap( + 0, n, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, + 0); + if (p == MAP_FAILED) { + p = 0; + } + else if (mprotect (static_cast<char*>(p), n, PROT_READ | PROT_WRITE | PROT_EXEC) == -1) + { + munmap (static_cast<char*>(p), n); + p = 0; + } +#elif defined SAL_W32 + p = VirtualAlloc(0, n, MEM_COMMIT, PAGE_EXECUTE_READWRITE); +#elif defined(SAL_OS2) + p = 0; + DosAllocMem( &p, n, PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_ANY); +#endif + if (p != 0) { + *size = n; + } + return p; +} + +extern "C" void SAL_CALL freeExec( + rtl_arena_type *, void * address, sal_Size size) +{ +#if defined SAL_UNX + munmap(static_cast< char * >(address), size); +#elif defined SAL_W32 + (void) size; // unused + VirtualFree(address, 0, MEM_RELEASE); +#elif defined(SAL_OS2) + (void) DosFreeMem( address); +#endif +} + +} + +class VtableFactory::GuardedBlocks: public std::vector< Block > { +public: + GuardedBlocks(VtableFactory const & factory): + m_factory(factory), m_guarded(true) {} + + ~GuardedBlocks(); + + void unguard() { m_guarded = false; } + +private: + GuardedBlocks(GuardedBlocks &); // not implemented + void operator =(GuardedBlocks); // not implemented + + VtableFactory const & m_factory; + bool m_guarded; +}; + +VtableFactory::GuardedBlocks::~GuardedBlocks() { + if (m_guarded) { + for (iterator i(begin()); i != end(); ++i) { + m_factory.freeBlock(*i); + } + } +} + +class VtableFactory::BaseOffset { +public: + BaseOffset(typelib_InterfaceTypeDescription * type) { calculate(type, 0); } + + sal_Int32 getFunctionOffset(rtl::OUString const & name) const + { return m_map.find(name)->second; } + +private: + sal_Int32 calculate( + typelib_InterfaceTypeDescription * type, sal_Int32 offset); + + typedef std::hash_map< rtl::OUString, sal_Int32, rtl::OUStringHash > Map; + + Map m_map; +}; + +sal_Int32 VtableFactory::BaseOffset::calculate( + typelib_InterfaceTypeDescription * type, sal_Int32 offset) +{ + rtl::OUString name(type->aBase.pTypeName); + if (m_map.find(name) == m_map.end()) { + for (sal_Int32 i = 0; i < type->nBaseTypes; ++i) { + offset = calculate(type->ppBaseTypes[i], offset); + } + m_map.insert(Map::value_type(name, offset)); + typelib_typedescription_complete( + reinterpret_cast< typelib_TypeDescription ** >(&type)); + offset += bridges::cpp_uno::shared::getLocalFunctions(type); + } + return offset; +} + +VtableFactory::VtableFactory(): m_arena( + rtl_arena_create( + "bridges::cpp_uno::shared::VtableFactory", + sizeof (void *), // to satisfy alignment requirements + 0, reinterpret_cast< rtl_arena_type * >(-1), allocExec, freeExec, 0)) +{ + if (m_arena == 0) { + throw std::bad_alloc(); + } +} + +VtableFactory::~VtableFactory() { + { + osl::MutexGuard guard(m_mutex); + for (Map::iterator i(m_map.begin()); i != m_map.end(); ++i) { + for (sal_Int32 j = 0; j < i->second.count; ++j) { + freeBlock(i->second.blocks[j]); + } + delete[] i->second.blocks; + } + } + rtl_arena_destroy(m_arena); +} + +VtableFactory::Vtables VtableFactory::getVtables( + typelib_InterfaceTypeDescription * type) +{ + rtl::OUString name(type->aBase.pTypeName); + osl::MutexGuard guard(m_mutex); + Map::iterator i(m_map.find(name)); + if (i == m_map.end()) { + GuardedBlocks blocks(*this); + createVtables(blocks, BaseOffset(type), type, true); + Vtables vtables; + OSL_ASSERT(blocks.size() <= SAL_MAX_INT32); + vtables.count = static_cast< sal_Int32 >(blocks.size()); + bridges::cpp_uno::shared::GuardedArray< Block > guardedBlocks( + new Block[vtables.count]); + vtables.blocks = guardedBlocks.get(); + for (sal_Int32 j = 0; j < vtables.count; ++j) { + vtables.blocks[j] = blocks[j]; + } + i = m_map.insert(Map::value_type(name, vtables)).first; + guardedBlocks.release(); + blocks.unguard(); + } + return i->second; +} + +#ifdef USE_DOUBLE_MMAP +bool VtableFactory::createBlock(Block &block, sal_Int32 slotCount) const +{ + sal_Size size = getBlockSize(slotCount); + sal_Size pagesize = sysconf(_SC_PAGESIZE); + block.size = (size + (pagesize - 1)) & ~(pagesize - 1); + block.start = block.exec = NULL; + block.fd = -1; + + osl::Security aSecurity; + rtl::OUString strDirectory; + rtl::OUString strURLDirectory; + if (aSecurity.getHomeDir(strURLDirectory)) + osl::File::getSystemPathFromFileURL(strURLDirectory, strDirectory); + + for (int i = strDirectory.getLength() == 0 ? 1 : 0; i < 2; ++i) + { + if (!strDirectory.getLength()) + strDirectory = rtl::OUString::createFromAscii("/tmp"); + + strDirectory += rtl::OUString::createFromAscii("/.execoooXXXXXX"); + rtl::OString aTmpName = rtl::OUStringToOString(strDirectory, osl_getThreadTextEncoding()); + char *tmpfname = new char[aTmpName.getLength()+1]; + strncpy(tmpfname, aTmpName.getStr(), aTmpName.getLength()+1); + if ((block.fd = mkstemp(tmpfname)) == -1) + perror("creation of executable memory area failed"); + if (block.fd == -1) + { + delete[] tmpfname; + break; + } + unlink(tmpfname); + delete[] tmpfname; + if (ftruncate(block.fd, block.size) == -1) + { + perror("truncation of executable memory area failed"); + close(block.fd); + block.fd = -1; + break; + } + block.start = mmap(NULL, block.size, PROT_READ | PROT_WRITE, MAP_SHARED, block.fd, 0); + if (block.start== MAP_FAILED) { + block.start = 0; + } + block.exec = mmap(NULL, block.size, PROT_READ | PROT_EXEC, MAP_SHARED, block.fd, 0); + if (block.exec == MAP_FAILED) { + block.exec = 0; + } + + //All good + if (block.start && block.exec && block.fd != -1) + break; + + freeBlock(block); + + strDirectory = rtl::OUString(); + } + if (!block.start || !block.exec || block.fd == -1) + { + //Fall back to non-doublemmaped allocation + block.fd = -1; + block.start = block.exec = rtl_arena_alloc(m_arena, &block.size); + } + return (block.start != 0 && block.exec != 0); +} + +void VtableFactory::freeBlock(Block const & block) const { + //if the double-map failed we were allocated on the arena + if (block.fd == -1 && block.start == block.exec && block.start != NULL) + rtl_arena_free(m_arena, block.start, block.size); + else + { + if (block.start) munmap(block.start, block.size); + if (block.exec) munmap(block.exec, block.size); + if (block.fd != -1) close(block.fd); + } +} +#else +bool VtableFactory::createBlock(Block &block, sal_Int32 slotCount) const +{ + block.size = getBlockSize(slotCount); + block.start = rtl_arena_alloc(m_arena, &block.size); + return block.start != 0; +} + +void VtableFactory::freeBlock(Block const & block) const { + rtl_arena_free(m_arena, block.start, block.size); +} +#endif + +void VtableFactory::createVtables( + GuardedBlocks & blocks, BaseOffset const & baseOffset, + typelib_InterfaceTypeDescription * type, bool includePrimary) const +{ + if (includePrimary) { + sal_Int32 slotCount + = bridges::cpp_uno::shared::getPrimaryFunctions(type); + Block block; + if (!createBlock(block, slotCount)) { + throw std::bad_alloc(); + } + try { + Slot * slots = initializeBlock(block.start, slotCount); + unsigned char * codeBegin = + reinterpret_cast< unsigned char * >(slots); + unsigned char * code = codeBegin; + sal_Int32 vtableOffset = blocks.size() * sizeof (Slot *); + for (typelib_InterfaceTypeDescription const * type2 = type; + type2 != 0; type2 = type2->pBaseTypeDescription) + { + code = addLocalFunctions( + &slots, code, +#ifdef USE_DOUBLE_MMAP + sal_IntPtr(block.exec) - sal_IntPtr(block.start), +#endif + type2, + baseOffset.getFunctionOffset(type2->aBase.pTypeName), + bridges::cpp_uno::shared::getLocalFunctions(type2), + vtableOffset); + } + flushCode(codeBegin, code); +#ifdef USE_DOUBLE_MMAP + //Finished generating block, swap writable pointer with executable + //pointer + ::std::swap(block.start, block.exec); +#endif + blocks.push_back(block); + } catch (...) { + freeBlock(block); + throw; + } + } + for (sal_Int32 i = 0; i < type->nBaseTypes; ++i) { + createVtables(blocks, baseOffset, type->ppBaseTypes[i], i != 0); + } +} diff --git a/bridges/source/cpp_uno/shared/vtables.cxx b/bridges/source/cpp_uno/shared/vtables.cxx new file mode 100644 index 000000000000..2779d928f24e --- /dev/null +++ b/bridges/source/cpp_uno/shared/vtables.cxx @@ -0,0 +1,154 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_bridges.hxx" + +#include "bridges/cpp_uno/shared/vtables.hxx" + +#include "osl/diagnose.h" +#include "sal/types.h" +#include "typelib/typedescription.h" + +#include <algorithm> + +namespace +{ + +/** + * Calculates the number of vtables associated with an interface type. + * + * <p>Multiple-inheritance C++ classes have more than one vtable.</p> + * + * @param type a non-null pointer to an interface type description + * @return the number of vtables associated with the given interface type + */ +sal_Int32 getVtableCount(typelib_InterfaceTypeDescription const * type) { + sal_Int32 n = 0; + for (sal_Int32 i = 0; i < type->nBaseTypes; ++i) { + n += getVtableCount(type->ppBaseTypes[i]); + } + return std::max< sal_Int32 >(n, 1); +} + +/** + * Maps a local member index to a local function index. + * + * <p><em>Local</em> members/functions are those not inherited from any base + * types. The number of <em>functions</em> is potentially larger than the + * number of <em>members</em>, as each read–write attribute member counts + * as two functions.</p> + * + * @param type a non-null pointer to an interface type description + * @param localMember a local member index, relative to the given interface type + * @return the local function index corresponding to the given local member + * index, relative to the given interface type + */ +sal_Int32 mapLocalMemberToLocalFunction( + typelib_InterfaceTypeDescription * type, sal_Int32 localMember) +{ + typelib_typedescription_complete( + reinterpret_cast< typelib_TypeDescription ** >(&type)); + sal_Int32 localMemberOffset = type->nAllMembers - type->nMembers; + sal_Int32 localFunctionOffset = type->nMapFunctionIndexToMemberIndex + - bridges::cpp_uno::shared::getLocalFunctions(type); + return type->pMapMemberIndexToFunctionIndex[localMemberOffset + localMember] + - localFunctionOffset; +} + +// Since on Solaris we compile with --instances=static, getVtableSlot cannot be +// a template function, with explicit instantiates for +// T = typelib_InterfaceAttributeTypeDescription and +// T = typelib_InterfaceMethodTypeDescription in this file; hence, there are two +// overloaded versions of getVtableSlot that both delegate to this template +// function: +template< typename T > bridges::cpp_uno::shared::VtableSlot doGetVtableSlot( + T const * ifcMember) +{ + bridges::cpp_uno::shared::VtableSlot slot; + slot.offset = 0; + T * member = const_cast< T * >(ifcMember); + while (member->pBaseRef != 0) { + OSL_ASSERT(member->nIndex < member->pInterface->nBaseTypes); + for (sal_Int32 i = 0; i < member->nIndex; ++i) { + slot.offset += getVtableCount(member->pInterface->ppBaseTypes[i]); + } + typelib_TypeDescription * desc = 0; + typelib_typedescriptionreference_getDescription( + &desc, member->pBaseRef); + OSL_ASSERT( + desc != 0 && desc->eTypeClass == member->aBase.aBase.eTypeClass); + if (member != ifcMember) { + typelib_typedescription_release(&member->aBase.aBase); + } + member = reinterpret_cast< T * >(desc); + } + slot.index + = bridges::cpp_uno::shared::getPrimaryFunctions( + member->pInterface->pBaseTypeDescription) + + mapLocalMemberToLocalFunction(member->pInterface, member->nIndex); + if (member != ifcMember) { + typelib_typedescription_release(&member->aBase.aBase); + } + return slot; +} + +} + +namespace bridges { namespace cpp_uno { namespace shared { + +sal_Int32 getLocalFunctions(typelib_InterfaceTypeDescription const * type) { + return type->nMembers == 0 + ? 0 + : (type->nMapFunctionIndexToMemberIndex + - type->pMapMemberIndexToFunctionIndex[ + type->nAllMembers - type->nMembers]); +} + +sal_Int32 getPrimaryFunctions(typelib_InterfaceTypeDescription * type) { + sal_Int32 n = 0; + for (; type != 0; type = type->pBaseTypeDescription) { + typelib_typedescription_complete( + reinterpret_cast< typelib_TypeDescription ** >(&type)); + n += getLocalFunctions(type); + } + return n; +} + +VtableSlot getVtableSlot( + typelib_InterfaceAttributeTypeDescription const * ifcMember) +{ + return doGetVtableSlot(ifcMember); +} + +VtableSlot getVtableSlot( + typelib_InterfaceMethodTypeDescription const * ifcMember) +{ + return doGetVtableSlot(ifcMember); +} + +} } } |