diff options
Diffstat (limited to 'bridges/source/cpp_uno/msvc_win32_x86-64')
-rw-r--r-- | bridges/source/cpp_uno/msvc_win32_x86-64/call.asm | 133 | ||||
-rw-r--r-- | bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx | 582 | ||||
-rw-r--r-- | bridges/source/cpp_uno/msvc_win32_x86-64/dllinit.cxx | 61 | ||||
-rw-r--r-- | bridges/source/cpp_uno/msvc_win32_x86-64/except.cxx | 850 | ||||
-rw-r--r-- | bridges/source/cpp_uno/msvc_win32_x86-64/makefile.mk | 83 | ||||
-rw-r--r-- | bridges/source/cpp_uno/msvc_win32_x86-64/mscx.hxx | 62 | ||||
-rw-r--r-- | bridges/source/cpp_uno/msvc_win32_x86-64/uno2cpp.cxx | 450 |
7 files changed, 2221 insertions, 0 deletions
diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/call.asm b/bridges/source/cpp_uno/msvc_win32_x86-64/call.asm new file mode 100644 index 000000000000..406e78d397a1 --- /dev/null +++ b/bridges/source/cpp_uno/msvc_win32_x86-64/call.asm @@ -0,0 +1,133 @@ +; -*- Mode: text; tab-width: 8; indent-tabs-mode: nil comment-column: 44; comment-start: ";; " comment-start-skip: ";; *" -*- + +;; Version: MPL 1.1 / GPLv3+ / LGPLv3+ +;; +;; The contents of this file are subject to the Mozilla Public License Version +;; 1.1 (the "License"); you may not use this file except in compliance with +;; the License or as specified alternatively below. You may obtain a copy of +;; the License at http://www.mozilla.org/MPL/ +;; +;; Software distributed under the License is distributed on an "AS IS" basis, +;; WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +;; for the specific language governing rights and limitations under the +;; License. +;; +;; The Initial Developer of the Original Code is +;; Novell, Inc. +;; Portions created by the Initial Developer are Copyright (C) 2011 +;; Novell, Inc. All Rights Reserved. +;; +;; Major Contributor(s): +;; Tor Lillqvist <tml@iki.fi> +;; Portions created by Tor Lillqvist are Copyright (C) 2011 Tor Lillqvist. All Rights Reserved. +;; +;; For minor contributions see the git repository. +;; +;; Alternatively, the contents of this file may be used under the terms of +;; either the GNU General Public License Version 3 or later (the "GPLv3+"), or +;; the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"), +;; in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable +;; instead of those above. + +;; This is the function jumped to from the trampoline generated by +;; codeSnippet() in cpp2uno.cxx. Here we call cpp_vtable_call() which +;; then calls the actual UNO function. + +;; The code snippet generated is called from "normal" C++ code which +;; has no idea that it is calling dynamically generated code. + +;; The generated short code snippet is not covered by any function +;; table and unwind info, but that doesn't matter, as the instructions +;; in it are not really going to cause any exception. Once it jumps +;; here it is covered by a function table, and the calls further down +;; through cpp_vtable_call() can be unwound cleanly. + +;; This is in a separate file for x86-64 as MSVC doesn't have in-line +;; assembly for x64. + +;; Random web links and other documentation about low-level +;; implementation details for the C++/UNO bridge on x64 Windows kept +;; here: + +;; Caolan's "Lazy Hackers Guide To Porting" is useful: +;; http://wiki.services.openoffice.org/wiki/Lazy_Hackers_Guide_To_Porting + +;; As for details about the x64 Windows calling convention, register +;; usage, stack usage, exception handling etc, the official +;; documentation (?) on MSDN is a bit fragmented and split up into a +;; needlessly large number of short pages. But still: +;; http://msdn.microsoft.com/en-us/library/7kcdt6fy%28v=VS.90%29.aspx + +;; Also see Raymond Chen's blog post: +;; http://blogs.msdn.com/b/oldnewthing/archive/2004/01/14/58579.aspx + +;; This one is actually more readable: "Improving Automated Analysis +;; of Windows x64 Binaries": http://www.uninformed.org/?v=4&a=1 + +;; This one has a mass of information about different architectures +;; and compilers, and contains some details about the x64 Windows +;; calling convention in particular that Microsoft doesn't mention +;; above: +;; http://www.agner.org/optimize/calling_conventions.pdf + +;; Random interesting discussion threads: +;; http://social.msdn.microsoft.com/Forums/en/vcgeneral/thread/300bd6d3-9381-4d2d-8129-e48b392c05d8 + +;; Ken Johnson's blog http://www.nynaeve.net/ has much interesting +;; information, for instance: +;; http://www.nynaeve.net/?p=11 + +typelib_TypeClass_FLOAT equ 10 +typelib_TypeClass_DOUBLE equ 11 + +extern cpp_vtable_call: proc + +.code + +privateSnippetExecutor proc frame + + ;; Make stack frame. Re-align RSP at 16 bytes. We need just one + ;; qword of stack for our own purposes: Where cpp_vtable_call() + ;; will store the return value of the UNO callee. But we of course + ;; must also allocate space for the functions we call (i.e., just + ;; cpp_vtable_call()) to spill their register parameters. + + sub rsp, 40 + .allocstack (40) + .endprolog + + ;; Call cpp_vtable_call() with 2 parameters: + + ;; 1 (rcx): nOffsetAndIndex (already put there in code generated by codeSnippet) + ;; 2 (rdx): pointer to where to store return value, followed by our + ;; return address (uninteresting to cpp_vtable_call()), followed + ;; by our spilled register parameters, as stored above, followed + ;; by the rest of our parameters, if any. + + lea rdx, 32[rsp] + + call cpp_vtable_call + + ;; cpp_vtable_call() returns the typelib_TypeClass type of the + ;; return value of the called UNO function + + cmp rax, typelib_TypeClass_FLOAT + je Lfloat + + cmp rax, typelib_TypeClass_DOUBLE + je Lfloat + + mov rax, qword ptr 32[rsp] + jmp Lepilogue + +Lfloat: + movsd xmm0, qword ptr 32[rsp] + +Lepilogue: + add rsp, 40 + ret +privateSnippetExecutor endp + +end + +; vim:set shiftwidth=4 softtabstop=4 expandtab: diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx b/bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx new file mode 100644 index 000000000000..ecfd957947c4 --- /dev/null +++ b/bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx @@ -0,0 +1,582 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 <malloc.h> + +#include <com/sun/star/uno/genfunc.hxx> +#include <uno/data.h> +#include <typelib/typedescription.hxx> + +#include "bridges/cpp_uno/shared/bridge.hxx" +#include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx" +#include "bridges/cpp_uno/shared/types.hxx" +#include "bridges/cpp_uno/shared/vtablefactory.hxx" + +#include "mscx.hxx" + +using namespace ::com::sun::star::uno; + +static inline typelib_TypeClass cpp2uno_call( + bridges::cpp_uno::shared::CppInterfaceProxy * pThis, + const typelib_TypeDescription * pMemberTD, + typelib_TypeDescriptionReference * pReturnTypeRef, // NULL indicates void return + sal_Int32 nParams, + typelib_MethodParameter * pParams, + void ** pStack ) +{ + // Return type + typelib_TypeDescription * pReturnTD = NULL; + if ( pReturnTypeRef ) + TYPELIB_DANGER_GET( &pReturnTD, pReturnTypeRef ); + + int nFirstRealParam = 3; // Index into pStack, past return + // value, return address and 'this' + // pointer. + + void * pUnoReturn = NULL; + void * pCppReturn = NULL; // Complex return ptr: if != NULL && != pUnoReturn, reconversion need + + if ( pReturnTD ) + { + if ( bridges::cpp_uno::shared::isSimpleType( pReturnTD ) ) + { + pUnoReturn = pStack; + } + else + { + pCppReturn = pStack[nFirstRealParam++]; + + pUnoReturn = ( bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTD ) + ? alloca( pReturnTD->nSize ) + : pCppReturn ); // direct way + } + } + + void ** pCppIncomingParams = pStack + nFirstRealParam; + + // Unlike this method for other archs, prefer clarity to + // micro-optimization, and allocate these array separately + + // Parameters passed to the UNO function + void ** pUnoArgs = (void **)alloca( sizeof(void *) * nParams ); + + // Parameters received from C++ + void ** pCppArgs = (void **)alloca( sizeof(void *) * nParams ); + + // Indexes of values this have to be converted (interface conversion C++<=>UNO) + int * pTempIndexes = + (int *)alloca( sizeof(int) * nParams ); + + // Type descriptions for reconversions + typelib_TypeDescription ** ppTempParamTD = + (typelib_TypeDescription **)alloca( sizeof(void *) * nParams ); + + int nTempIndexes = 0; + + for ( int nPos = 0; nPos < nParams; ++nPos ) + { + const typelib_MethodParameter & rParam = pParams[nPos]; + + typelib_TypeDescription * pParamTD = NULL; + TYPELIB_DANGER_GET( &pParamTD, rParam.pTypeRef ); + + if ( !rParam.bOut && + bridges::cpp_uno::shared::isSimpleType( pParamTD ) ) + { + pCppArgs[nPos] = pUnoArgs[nPos] = pCppIncomingParams++; + + TYPELIB_DANGER_RELEASE( pParamTD ); + } + else // ptr to complex value | ref + { + void * pCppStack; + + pCppArgs[nPos] = pCppStack = *pCppIncomingParams++; + + if ( !rParam.bIn ) // Pure out + { + // UNO out is unconstructed mem + pUnoArgs[nPos] = alloca( pParamTD->nSize ); + pTempIndexes[nTempIndexes] = nPos; + // pParamTD will be released at reconversion + ppTempParamTD[nTempIndexes++] = pParamTD; + } + // + else if ( bridges::cpp_uno::shared::relatesToInterfaceType( pParamTD ) ) + { + ::uno_copyAndConvertData( + pUnoArgs[nPos] = alloca( pParamTD->nSize ), + pCppStack, pParamTD, + pThis->getBridge()->getCpp2Uno() ); + pTempIndexes[nTempIndexes] = nPos; // Has to be reconverted + // pParamTD will be released at reconversion + ppTempParamTD[nTempIndexes++] = pParamTD; + } + else // direct way + { + pUnoArgs[nPos] = pCppStack; + // No longer needed + TYPELIB_DANGER_RELEASE( pParamTD ); + } + } + } + + // ExceptionHolder + uno_Any aUnoExc; // Any will be constructed by callee + uno_Any * pUnoExc = &aUnoExc; + + // invoke UNO dispatch call + (*pThis->getUnoI()->pDispatcher)( + pThis->getUnoI(), pMemberTD, pUnoReturn, pUnoArgs, &pUnoExc ); + + // in case an exception occurred... + if ( pUnoExc ) + { + // Destruct temporary in/inout params + while ( nTempIndexes-- ) + { + int nIndex = pTempIndexes[nTempIndexes]; + + if ( pParams[nIndex].bIn ) // Is in/inout => was constructed + { + ::uno_destructData( pUnoArgs[nIndex], ppTempParamTD[nTempIndexes], 0 ); + } + TYPELIB_DANGER_RELEASE( ppTempParamTD[nTempIndexes] ); + } + if ( pReturnTD ) + TYPELIB_DANGER_RELEASE( pReturnTD ); + + CPPU_CURRENT_NAMESPACE::mscx_raiseException( + &aUnoExc, pThis->getBridge()->getUno2Cpp() ); // Has to destruct the any + + // Is here for dummy + return typelib_TypeClass_VOID; + } + else // Else, no exception occurred... + { + // Temporary params + while (nTempIndexes--) + { + int nIndex = pTempIndexes[nTempIndexes]; + typelib_TypeDescription * pParamTD = ppTempParamTD[nTempIndexes]; + + if ( pParams[nIndex].bOut ) // inout/out + { + // Convert and assign + ::uno_destructData( + pCppArgs[nIndex], pParamTD, cpp_release ); + ::uno_copyAndConvertData( + pCppArgs[nIndex], pUnoArgs[nIndex], pParamTD, + pThis->getBridge()->getUno2Cpp() ); + } + // Destroy temp UNO param + ::uno_destructData( pUnoArgs[nIndex], pParamTD, 0 ); + + TYPELIB_DANGER_RELEASE( pParamTD ); + } + // Return + if ( pCppReturn ) // Has complex return + { + if ( pUnoReturn != pCppReturn ) // Needs reconversion + { + ::uno_copyAndConvertData( + pCppReturn, pUnoReturn, pReturnTD, + pThis->getBridge()->getUno2Cpp() ); + // Destroy temp UNO return + ::uno_destructData( pUnoReturn, pReturnTD, 0 ); + } + // Complex return ptr is set to eax + pStack[0] = pCppReturn; + } + if ( pReturnTD ) + { + typelib_TypeClass eRet = (typelib_TypeClass)pReturnTD->eTypeClass; + TYPELIB_DANGER_RELEASE( pReturnTD ); + return eRet; + } + else + return typelib_TypeClass_VOID; + } +} + +extern "C" typelib_TypeClass cpp_vtable_call( + sal_Int64 nOffsetAndIndex, + void ** pStack ) +{ + sal_Int32 nFunctionIndex = (nOffsetAndIndex & 0xFFFFFFFF); + sal_Int32 nVtableOffset = ((nOffsetAndIndex >> 32) & 0xFFFFFFFF); + + // pStack points to space for return value allocated by + // privateSnippetExecutor() in call.asm, after which follows our + // return address (uninteresting), then the integer or + // floating-point register parameters (spilled by + // privateSnippetExecutor()) from the call to the trampoline, + // followed by stacked parameters. The first parameter is the + // 'this' pointer. If the callee returns a large value, the + // parameter after that is actually a pointer to where the callee + // should store its return value. + + void * pThis = static_cast<char *>( pStack[2] ) - nVtableOffset; + + bridges::cpp_uno::shared::CppInterfaceProxy * pCppI = + bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( pThis ); + + typelib_InterfaceTypeDescription * pTD = pCppI->getTypeDescr(); + + OSL_ENSURE( nFunctionIndex < pTD->nMapFunctionIndexToMemberIndex, "### illegal vtable index!\n" ); + if ( nFunctionIndex >= pTD->nMapFunctionIndexToMemberIndex ) + throw RuntimeException( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Illegal vtable index!")), + reinterpret_cast<XInterface *>( pCppI ) ); + + // Determine called method + int nMemberPos = pTD->pMapFunctionIndexToMemberIndex[nFunctionIndex]; + OSL_ENSURE( nMemberPos < pTD->nAllMembers, "### illegal member index!\n" ); + + TypeDescription aMemberDescr( pTD->ppAllMembers[nMemberPos] ); + + typelib_TypeClass eRet; + switch ( aMemberDescr.get()->eTypeClass ) + { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + { + typelib_TypeDescriptionReference *pAttrTypeRef = + reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( aMemberDescr.get() )->pAttributeTypeRef; + + if ( pTD->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex ) + { + // is GET method + eRet = cpp2uno_call( pCppI, aMemberDescr.get(), pAttrTypeRef, + 0, NULL, // No params + pStack ); + } + else + { + // is SET method + typelib_MethodParameter aParam; + aParam.pTypeRef = pAttrTypeRef; + aParam.bIn = sal_True; + aParam.bOut = sal_False; + + eRet = cpp2uno_call( pCppI, aMemberDescr.get(), + NULL, // Indicates void return + 1, &aParam, + pStack ); + } + break; + } + case typelib_TypeClass_INTERFACE_METHOD: + { + // is METHOD + switch ( nFunctionIndex ) + { + case 1: // acquire() + pCppI->acquireProxy(); // Non virtual call! + eRet = typelib_TypeClass_VOID; + break; + case 2: // release() + pCppI->releaseProxy(); // non virtual call! + eRet = typelib_TypeClass_VOID; + break; + case 0: // queryInterface() opt + { + typelib_TypeDescription * pTD = NULL; + + // the incoming C++ parameters are: The this + // pointer, the hidden return value pointer, and + // then the actual queryInterface() only + // parameter. Thus pStack[4].. + + TYPELIB_DANGER_GET( &pTD, reinterpret_cast<Type *>( pStack[4] )->getTypeLibType() ); + + if ( pTD ) + { + XInterface * pInterface = NULL; + (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface) + ( pCppI->getBridge()->getCppEnv(), + (void **)&pInterface, + pCppI->getOid().pData, + reinterpret_cast<typelib_InterfaceTypeDescription *>( pTD ) ); + + if ( pInterface ) + { + // pStack[3] = hidden return value pointer + ::uno_any_construct( reinterpret_cast<uno_Any *>( pStack[3] ), + &pInterface, pTD, cpp_acquire ); + + pInterface->release(); + TYPELIB_DANGER_RELEASE( pTD ); + + eRet = typelib_TypeClass_ANY; + break; + } + TYPELIB_DANGER_RELEASE( pTD ); + } + } // Fall through! + default: + { + typelib_InterfaceMethodTypeDescription * pMethodTD = + reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( aMemberDescr.get() ); + + eRet = cpp2uno_call( pCppI, aMemberDescr.get(), + pMethodTD->pReturnTypeRef, + pMethodTD->nParams, + pMethodTD->pParams, + pStack ); + } + } + break; + } + default: + { + throw RuntimeException( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("No member description found!")), + reinterpret_cast<XInterface *>( pCppI ) ); + // is here for dummy + eRet = typelib_TypeClass_VOID; + } + } + + return eRet; +} + +int const codeSnippetSize = 48; + +extern "C" char privateSnippetExecutor; + +// This function generates the code that acts as a proxy for the UNO function to be called. +// The generated code does the following: +// - Spills register parameters on stack +// - Loads functionIndex and vtableOffset into scratch registers +// - Jumps to privateSnippetExecutor + +unsigned char * codeSnippet( + unsigned char * code, + char param_kind[4], + sal_Int32 nFunctionIndex, + sal_Int32 nVtableOffset ) +{ + sal_uInt64 nOffsetAndIndex = ( ( (sal_uInt64) nVtableOffset ) << 32 ) | ( (sal_uInt64) nFunctionIndex ); + unsigned char *p = code; + + // Spill parameters + if ( param_kind[0] == CPPU_CURRENT_NAMESPACE::REGPARAM_INT ) + { + // mov qword ptr 8[rsp], rcx + *p++ = 0x48; *p++ = 0x89; *p++ = 0x4C; *p++ = 0x24; *p++ = 0x08; + } + else + { + // movsd qword ptr 8[rsp], xmm0 + *p++ = 0xF2; *p++ = 0x0F; *p++ = 0x11; *p++ = 0x44; *p++ = 0x24; *p++ = 0x08; + } + if ( param_kind[1] == CPPU_CURRENT_NAMESPACE::REGPARAM_INT ) + { + // mov qword ptr 16[rsp], rdx + *p++ = 0x48; *p++ = 0x89; *p++ = 0x54; *p++ = 0x24; *p++ = 0x10; + } + else + { + // movsd qword ptr 16[rsp], xmm1 + *p++ = 0xF2; *p++ = 0x0F; *p++ = 0x11; *p++ = 0x4C; *p++ = 0x24; *p++ = 0x10; + } + if ( param_kind[2] == CPPU_CURRENT_NAMESPACE::REGPARAM_INT ) + { + // mov qword ptr 24[rsp], r8 + *p++ = 0x4C; *p++ = 0x89; *p++ = 0x44; *p++ = 0x24; *p++ = 0x18; + } + else + { + // movsd qword ptr 24[rsp], xmm2 + *p++ = 0xF2; *p++ = 0x0F; *p++ = 0x11; *p++ = 0x54; *p++ = 0x24; *p++ = 0x18; + } + if ( param_kind[3] == CPPU_CURRENT_NAMESPACE::REGPARAM_INT ) + { + // mov qword ptr 32[rsp], r9 + *p++ = 0x4C;*p++ = 0x89; *p++ = 0x4C; *p++ = 0x24; *p++ = 0x20; + } + else + { + // movsd qword ptr 32[rsp], xmm3 + *p++ = 0xF2; *p++ = 0x0F; *p++ = 0x11; *p++ = 0x5C; *p++ = 0x24; *p++ = 0x20; + } + + // mov rcx, nOffsetAndIndex + *p++ = 0x48; *p++ = 0xB9; + *((sal_uInt64 *)p) = nOffsetAndIndex; p += 8; + + // mov r11, privateSnippetExecutor + *p++ = 0x49; *p++ = 0xBB; + *((void **)p) = &privateSnippetExecutor; p += 8; + + // jmp r11 + *p++ = 0x41; *p++ = 0xFF; *p++ = 0xE3; + + OSL_ASSERT( p < code + codeSnippetSize ); + + 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) + 1; +} + +sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize( + sal_Int32 slotCount ) +{ + return (slotCount + 1) * sizeof (Slot) + slotCount * codeSnippetSize; +} + +bridges::cpp_uno::shared::VtableFactory::Slot * +bridges::cpp_uno::shared::VtableFactory::initializeBlock( + void * block, + sal_Int32 slotCount ) +{ + struct Rtti { + sal_Int32 n0, n1, n2; + type_info * rtti; + Rtti(): + n0(0), n1(0), n2(0), + rtti(CPPU_CURRENT_NAMESPACE::mscx_getRTTI( + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.uno.XInterface")))) + {} + }; + static Rtti rtti; + + Slot * slots = mapBlockToVtable(block); + slots[-1].fn = &rtti; + return slots + slotCount; +} + +unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions( + Slot ** slots, + unsigned char * code, + typelib_InterfaceTypeDescription const * type, + sal_Int32 nFunctionOffset, + sal_Int32 functionCount, + sal_Int32 nVtableOffset ) +{ + (*slots) -= functionCount; + Slot * s = *slots; + + for (int member = 0; member < type->nMembers; ++member) { + typelib_TypeDescription * pTD = NULL; + + TYPELIB_DANGER_GET( &pTD, type->ppMembers[ member ] ); + OSL_ASSERT( pTD ); + + char param_kind[4]; + int nr = 0; + + for (int i = 0; i < 4; ++i) + param_kind[i] = CPPU_CURRENT_NAMESPACE::REGPARAM_INT; + + // 'this' + ++nr; + + if ( pTD->eTypeClass == typelib_TypeClass_INTERFACE_ATTRIBUTE ) + { + typelib_InterfaceAttributeTypeDescription * pIfaceAttrTD = + reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( pTD ); + + // Getter + + (s++)->fn = code; + code = codeSnippet( code, param_kind, nFunctionOffset++, nVtableOffset ); + if ( ! pIfaceAttrTD->bReadOnly ) + { + typelib_TypeDescription * pAttrTD = NULL; + TYPELIB_DANGER_GET( &pAttrTD, pIfaceAttrTD->pAttributeTypeRef ); + OSL_ASSERT( pAttrTD ); + + // Setter + if ( pAttrTD->eTypeClass == typelib_TypeClass_FLOAT || + pAttrTD->eTypeClass == typelib_TypeClass_DOUBLE ) + param_kind[nr++] = CPPU_CURRENT_NAMESPACE::REGPARAM_FLT; + + TYPELIB_DANGER_RELEASE( pAttrTD ); + + (s++)->fn = code; + code = codeSnippet( code, param_kind, nFunctionOffset++, nVtableOffset ); + } + } + else if ( pTD->eTypeClass == typelib_TypeClass_INTERFACE_METHOD ) + { + typelib_InterfaceMethodTypeDescription * pMethodTD = + reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( pTD ); + + typelib_TypeDescription * pReturnTD = NULL; + TYPELIB_DANGER_GET( &pReturnTD, pMethodTD->pReturnTypeRef ); + OSL_ASSERT( pReturnTD ); + + if ( !bridges::cpp_uno::shared::isSimpleType( pReturnTD ) ) + { + // Return value + ++nr; + } + + for (int param = 0; nr < 4 && param < pMethodTD->nParams; ++param, ++nr) + { + typelib_TypeDescription * pParamTD = NULL; + + TYPELIB_DANGER_GET( &pParamTD, pMethodTD->pParams[param].pTypeRef ); + OSL_ASSERT( pParamTD ); + + if ( pParamTD->eTypeClass == typelib_TypeClass_FLOAT || + pParamTD->eTypeClass == typelib_TypeClass_DOUBLE ) + param_kind[nr] = CPPU_CURRENT_NAMESPACE::REGPARAM_FLT; + + TYPELIB_DANGER_RELEASE( pParamTD ); + } + (s++)->fn = code; + code = codeSnippet( code, param_kind, nFunctionOffset++, nVtableOffset ); + + TYPELIB_DANGER_RELEASE( pReturnTD ); + } + else + OSL_ASSERT( false ); + + TYPELIB_DANGER_RELEASE( pTD ); + } + return code; +} + +void bridges::cpp_uno::shared::VtableFactory::flushCode( + unsigned char const *, + unsigned char const * ) +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/dllinit.cxx b/bridges/source/cpp_uno/msvc_win32_x86-64/dllinit.cxx new file mode 100644 index 000000000000..cfbc58650f0d --- /dev/null +++ b/bridges/source/cpp_uno/msvc_win32_x86-64/dllinit.cxx @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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" + + +#pragma warning(push,1) // disable warnings within system headers +#include <windows.h> +#pragma warning(pop) + + +void dso_init(void); +void dso_exit(void); + + +extern "C" BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpvReserved) +{ + switch(dwReason) { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hModule); + + dso_init(); + break; + + case DLL_PROCESS_DETACH: + if (!lpvReserved) + dso_exit(); + break; + } + + return TRUE; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/except.cxx b/bridges/source/cpp_uno/msvc_win32_x86-64/except.cxx new file mode 100644 index 000000000000..2157568ad915 --- /dev/null +++ b/bridges/source/cpp_uno/msvc_win32_x86-64/except.cxx @@ -0,0 +1,850 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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. + * + ************************************************************************/ + +// Interesting info can be found in: + +// MSDN, obviously + +// http://www.osronline.com/article.cfm?article=469 + +// ONTL, "Open NT Native Template Library", a C++ STL-like library +// that can be used even when writing Windows drivers. This is some +// quite badass code. The author has done impressive heavy spelunking +// of MSVCR structures. http://code.google.com/p/ontl/ + +// Geoff Chappell's pages: +// http://members.ozemail.com.au/~geoffch/samples/programming/msvc/language/index.html + +// The below is from ONTL's ntl/nt/exception.hxx, cleaned up to keep just the _M_X64 parts: + +#if 0 + +/* This information until the corresponding '#endif // 0' is covered + * by ONTL's license, which is said to be the "zlib/libgng license" + * below, which as far as I see is permissive enough to allow this + * information to be included here in this source file. Note that no + * actual code from ONTL below gets compiled into the object file. + */ + +/* + * Copyright (c) 2011 <copyright holders> (The ONTL main + * developer(s) don't tell their real name(s) on the ONTL site.) + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + */ + +typedef uint32_t rva_t; + +///\note the calling convention should not matter since this has no arguments +typedef void generic_function_t(); + +struct ptrtomember // _PMD +{ + typedef __w64 int32_t mdiff_t; + mdiff_t member_offset; + mdiff_t vbtable_offset; // -1 if not a virtual base + mdiff_t vdisp_offset; // offset to the displacement value inside the vbtable + + template<typename T> + T * operator()(T * const thisptr) const + { + uintptr_t tp = reinterpret_cast<uintptr_t>(thisptr); + uintptr_t ptr = tp + member_offset; + if ( vbtable_offset != -1 ) // !(vbtable_offset < 0) + { + ptr += *reinterpret_cast<mdiff_t*>( static_cast<intptr_t>(vdisp_offset + *reinterpret_cast<mdiff_t*>(tp + vbtable_offset)) ) + + vbtable_offset; + } + return reinterpret_cast<T*>(ptr); + } +}; + +struct eobject +{ + typedef void (* dtor_ptr )(eobject*); + typedef void (* ctor_ptr )(eobject*, eobject*); + typedef void (* ctor_ptr2)(eobject*, eobject*, int); +}; + +struct catchabletype +{ + /** is simple type */ + uint32_t memmoveable : 1; + /** catchable as reference only */ + uint32_t refonly : 1; + /** class with virtual base */ + uint32_t hasvirtbase : 1; + /** offset to the type descriptor */ + rva_t typeinfo; + + /** catch type instance location within a thrown object */ + ptrtomember thiscast; + /** size of the simple type or offset into buffer of \c this pointer for catch object */ + uint32_t object_size; + + union + { + rva_t copyctor; + rva_t copyctor2; + }; +}; + +#pragma pack(push, 4) +struct catchabletypearray +{ + uint32_t size; + rva_t type[1]; +}; +#pragma pack(pop) + +#pragma pack(push, 4) +struct throwinfo +{ + typedef exception_disposition __cdecl forwardcompathandler_t(...); + + /* 0x00 */ uint32_t econst : 1; + /* 0x00 */ uint32_t evolatile : 1; + /* 0x00 */ uint32_t : 1; + /* 0x00 */ uint32_t e8 : 1; + /* 0x04 */ rva_t exception_dtor; + /* 0x08 */ rva_t forwardcompathandler; + /* 0x0C */ rva_t catchabletypearray; ///< types able to catch the exception. +}; +#pragma pack(pop) + +/// This type represents the catch clause +struct ehandler +{ + // union { uint32_t adjectives; void * ptr; }; + uint32_t isconst : 1; + uint32_t isvolatile : 1; + uint32_t isunaligned : 1;// guess it is not used on x86 + uint32_t isreference : 1; + + uint32_t :27; + uint32_t ishz : 1; + + /** offset to the type descriptor of this catch object */ + /*0x04*/ rva_t typeinfo; // dispType + /*0x08*/ int eobject_bpoffset; // dispCatchObj + /** offset to the catch clause funclet */ + /*0x0C*/ rva_t handler; // dispOfHandler + /*0x10*/ uint32_t frame; // dispFrame +} + +// ___BuildCatchObject +/// 15.3/16 When the exception-declaration specifies a class type, a copy +/// constructor is used to initialize either the object declared +/// in the exception-declaration or, +/// if the exception-declaration does not specify a name, +/// a temporary object of that type. +///\note This is the question may we optimize out the last case. +///\warning If the copy constructor throws an exception, std::unexpected would be called +void + constructcatchobject( + cxxregistration * cxxreg, + const ehandler * const catchblock, + catchabletype * const convertable, + const dispatcher_context* const dispatch + ) + const +{ + _EH_TRACE_ENTER(); + // build helper + __try { + struct typeinfo_t { void* vtbl; void* spare; char name[1]; }; + enum catchable_info { cidefault, cicomplex, civirtual } cinfo = cidefault; + + const typeinfo_t* ti = catchblock->typeinfo ? dispatch->va<typeinfo_t*>(catchblock->typeinfo) : NULL; + if(ti && *ti->name && (catchblock->eobject_bpoffset || catchblock->ishz)){ + eobject** objplace = catchblock->ishz + ? reinterpret_cast<eobject**>(cxxreg) + : reinterpret_cast<eobject**>(catchblock->eobject_bpoffset + cxxreg->fp.FramePointers); + if(catchblock->isreference){ + // just ref/pointer + *objplace = adjust_pointer(get_object(), convertable); + }else if(convertable->memmoveable){ + // POD + std::memcpy(objplace, get_object(), convertable->object_size); + if(convertable->object_size == sizeof(void*) && *objplace) + *objplace = adjust_pointer((void*)*objplace, convertable); + }else{ + // if copy ctor exists, call it; binary copy otherwise + if(convertable->copyctor){ + cinfo = convertable->hasvirtbase ? civirtual : cicomplex; + }else{ + std::memcpy(objplace, (const void*)adjust_pointer(get_object(), convertable), convertable->object_size); + } + } + } + // end of build helper + if(cinfo != cidefault){ + eobject* objthis = catchblock->ishz + ? reinterpret_cast<eobject*>(cxxreg) + : reinterpret_cast<eobject*>(catchblock->eobject_bpoffset + cxxreg->fp.FramePointers); + void* copyctor = thrown_va(convertable->copyctor); + eobject* copyarg = adjust_pointer(get_object(), convertable); + if(cinfo == cicomplex) + (eobject::ctor_ptr (copyctor))(objthis, copyarg); + else + (eobject::ctor_ptr2(copyctor))(objthis, copyarg, 1); + } + } + __except(cxxregistration::unwindfilter(static_cast<nt::ntstatus>(_exception_code()))) + { + nt::exception::inconsistency(); + } + _EH_TRACE_LEAVE(); +} + +#endif // 0 + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_bridges.hxx" + +#pragma warning( disable : 4237 ) +#include <boost/unordered_map.hpp> +#include <sal/config.h> +#include <malloc.h> +#include <new.h> +#include <typeinfo.h> +#include <signal.h> + +#include "rtl/alloc.h" +#include "rtl/strbuf.hxx" +#include "rtl/ustrbuf.hxx" + +#include "com/sun/star/uno/Any.hxx" + +#include "mscx.hxx" + +#pragma pack(push, 8) + +using namespace ::com::sun::star::uno; +using namespace ::std; +using namespace ::osl; +using namespace ::rtl; + +namespace CPPU_CURRENT_NAMESPACE +{ + +static inline OUString toUNOname( + OUString const & rRTTIname ) + throw () +{ + OUStringBuffer aRet( 64 ); + OUString aStr( rRTTIname.copy( 4, rRTTIname.getLength()-4-2 ) ); // filter .?AUzzz@yyy@xxx@@ + sal_Int32 nPos = aStr.getLength(); + while (nPos > 0) + { + sal_Int32 n = aStr.lastIndexOf( '@', nPos ); + aRet.append( aStr.copy( n +1, nPos -n -1 ) ); + if (n >= 0) + { + aRet.append( (sal_Unicode)'.' ); + } + nPos = n; + } + return aRet.makeStringAndClear(); +} + +static inline OUString toRTTIname( + OUString const & rUNOname ) + throw () +{ + OUStringBuffer aRet( 64 ); + aRet.appendAscii( RTL_CONSTASCII_STRINGPARAM(".?AV") ); // class ".?AV"; struct ".?AU" + sal_Int32 nPos = rUNOname.getLength(); + while (nPos > 0) + { + sal_Int32 n = rUNOname.lastIndexOf( '.', nPos ); + aRet.append( rUNOname.copy( n +1, nPos -n -1 ) ); + aRet.append( (sal_Unicode)'@' ); + nPos = n; + } + aRet.append( (sal_Unicode)'@' ); + return aRet.makeStringAndClear(); +} + +//RTTI simulation + +typedef boost::unordered_map< OUString, void *, OUStringHash, equal_to< OUString > > t_string2PtrMap; + +class RTTInfos +{ + Mutex _aMutex; + t_string2PtrMap _allRTTI; + + static OUString toRawName( OUString const & rUNOname ) throw (); +public: + type_info * getRTTI( OUString const & rUNOname ) throw (); + + RTTInfos(); + ~RTTInfos(); +}; + +class __type_info +{ + friend type_info * RTTInfos::getRTTI( OUString const & ) throw (); + friend int mscx_filterCppException( + LPEXCEPTION_POINTERS, uno_Any *, uno_Mapping * ); + +public: + virtual ~__type_info() throw (); + + inline __type_info( void * m_data, const char * m_d_name ) throw () + : _m_data( m_data ) + { ::strcpy( _m_d_name, m_d_name ); } // #100211# - checked + +private: + void * _m_data; + char _m_d_name[1]; +}; + +__type_info::~__type_info() throw () +{ +} + +type_info * RTTInfos::getRTTI( OUString const & rUNOname ) throw () +{ + // a must be + OSL_ENSURE( sizeof(__type_info) == sizeof(type_info), "### type info structure size differ!" ); + + MutexGuard aGuard( _aMutex ); + t_string2PtrMap::const_iterator const iFind( _allRTTI.find( rUNOname ) ); + + // check if type is already available + if (iFind == _allRTTI.end()) + { + // insert new type_info + OString aRawName( OUStringToOString( toRTTIname( rUNOname ), RTL_TEXTENCODING_ASCII_US ) ); + __type_info * pRTTI = new( ::rtl_allocateMemory( sizeof(__type_info) + aRawName.getLength() ) ) + __type_info( NULL, aRawName.getStr() ); + + // put into map + pair< t_string2PtrMap::iterator, bool > insertion( + _allRTTI.insert( t_string2PtrMap::value_type( rUNOname, pRTTI ) ) ); + OSL_ENSURE( insertion.second, "### rtti insertion failed?!" ); + + return (type_info *)pRTTI; + } + else + { + return (type_info *)iFind->second; + } +} + +RTTInfos::RTTInfos() throw () +{ +} + +RTTInfos::~RTTInfos() throw () +{ +#if OSL_DEBUG_LEVEL > 1 + OSL_TRACE( "> freeing generated RTTI infos... <\n" ); +#endif + + MutexGuard aGuard( _aMutex ); + for ( t_string2PtrMap::const_iterator iPos( _allRTTI.begin() ); + iPos != _allRTTI.end(); ++iPos ) + { + __type_info * pType = (__type_info *)iPos->second; + pType->~__type_info(); // obsolete, but good style... + ::rtl_freeMemory( pType ); + } +} + +void * __cdecl copyConstruct( + void * pExcThis, + void * pSource, + typelib_TypeDescription * pTD ) throw () +{ + ::uno_copyData( pExcThis, pSource, pTD, cpp_acquire ); + return pExcThis; +} + +void * __cdecl destruct( + void * pExcThis, + typelib_TypeDescription * pTD ) throw () +{ + ::uno_destructData( pExcThis, pTD, cpp_release ); + return pExcThis; +} + +const int codeSnippetSize = 40; + +void GenerateConstructorTrampoline( + unsigned char * code, + typelib_TypeDescription * pTD ) throw () +{ + unsigned char *p = code; + + // mov r8, pTD + *p++ = 0x49; *p++ = 0xB8; + *((void **)p) = pTD; p += 8; + + // mov r11, copyConstruct + *p++ = 0x49; *p++ = 0xBB; + *((void **)p) = ©Construct; p += 8; + + // jmp r11 + *p++ = 0x41; *p++ = 0xFF; *p++ = 0xE3; + + OSL_ASSERT( p < code + codeSnippetSize ); +} + +void GenerateDestructorTrampoline( + unsigned char * code, + typelib_TypeDescription * pTD ) throw () +{ + unsigned char *p = code; + + // mov rdx, pTD + *p++ = 0x48; *p++ = 0xBA; + *((void **)p) = pTD; p += 8; + + // mov r11, destruct + *p++ = 0x49; *p++ = 0xBB; + *((void **)p) = &destruct; p += 8; + + // jmp r11 + *p++ = 0x41; *p++ = 0xFF; *p++ = 0xE3; + + OSL_ASSERT( p < code + codeSnippetSize ); +} + +// This looks like it is the struct catchabletype above + +struct ExceptionType +{ + sal_Int32 _n0; // flags + sal_uInt32 _pTypeInfo; // typeinfo + sal_Int32 _n1, _n2, _n3; // thiscast + sal_Int32 _n4; // object_size + sal_uInt32 _pCopyCtor; // copyctor + + inline ExceptionType( + sal_uChar * pCode, + sal_uInt64 pCodeBase, + typelib_TypeDescription * pTD ) throw () + : _n0( 0 ) + , _n1( 0 ) + , _n2( -1 ) + , _n3( 0 ) + , _n4( pTD->nSize ) + { + // As _n0 is always initialized to zero, that means the + // hasvirtbase flag (see the ONTL catchabletype struct) is + // off, and thus the copyctor is of the ctor_ptr kind. + _pTypeInfo = (sal_uInt32) ((sal_uInt64) mscx_getRTTI( pTD->pTypeName ) - pCodeBase); + GenerateConstructorTrampoline( pCode, pTD ); + _pCopyCtor = (sal_uInt32) ((sal_uInt64) pCode - pCodeBase); + } + inline ~ExceptionType() throw () + { + } +}; + +struct RaiseInfo; + +class ExceptionInfos +{ + Mutex _aMutex; + t_string2PtrMap _allRaiseInfos; + +public: + static RaiseInfo * getRaiseInfo( typelib_TypeDescription * pTD ) throw (); + + static DWORD allocationGranularity; + + ExceptionInfos() throw (); + ~ExceptionInfos() throw (); +}; + +DWORD ExceptionInfos::allocationGranularity = 0; + +// This corresponds to the struct throwinfo described above. + +struct RaiseInfo +{ + sal_Int32 _n0; + sal_uInt32 _pDtor; + sal_Int32 _n2; + sal_uInt32 _types; + + // Additional fields + typelib_TypeDescription * _pTD; + sal_uChar * _code; + sal_uInt64 _codeBase; + + RaiseInfo( typelib_TypeDescription * pTD ) throw (); + + ~RaiseInfo() throw (); +}; + +RaiseInfo::RaiseInfo( typelib_TypeDescription * pTD )throw () + : _n0( 0 ) + , _n2( 0 ) + , _pTD( pTD ) +{ + typelib_CompoundTypeDescription * pCompTD; + + // Count how many trampolines we need + int codeSize = codeSnippetSize; + + // Info count + int nLen = 0; + for ( pCompTD = (typelib_CompoundTypeDescription*)pTD; + pCompTD; pCompTD = pCompTD->pBaseTypeDescription ) + { + ++nLen; + codeSize += codeSnippetSize; + } + + sal_uChar * pCode = _code = (sal_uChar *)::rtl_allocateMemory( codeSize ); + + _codeBase = (sal_uInt64)pCode & ~(ExceptionInfos::allocationGranularity-1); + + DWORD old_protect; +#if OSL_DEBUG_LEVEL > 0 + BOOL success = +#endif + VirtualProtect( pCode, codeSize, PAGE_EXECUTE_READWRITE, &old_protect ); + OSL_ENSURE( success, "VirtualProtect() failed!" ); + + ::typelib_typedescription_acquire( pTD ); + + GenerateDestructorTrampoline( pCode, pTD ); + _pDtor = (sal_Int32)((sal_uInt64)pCode - _codeBase); + pCode += codeSnippetSize; + + // Info count accompanied by type info ptrs: type, base type, base base type, ... + _types = (sal_Int32)((sal_uInt64)::rtl_allocateMemory( 4 + 4* nLen) - _codeBase); + *(sal_Int32 *)_types = nLen; + + ExceptionType ** ppTypes = (ExceptionType **)((sal_Int32 *)_types + 1); + + int nPos = 0; + for ( pCompTD = (typelib_CompoundTypeDescription*)pTD; + pCompTD; pCompTD = pCompTD->pBaseTypeDescription ) + { + ppTypes[nPos++] = + new ExceptionType( pCode, _codeBase, + (typelib_TypeDescription *)pCompTD ); + pCode += codeSnippetSize; + } +} + +RaiseInfo::~RaiseInfo() throw () +{ + sal_uInt32 * pTypes = + (sal_uInt32 *)(_codeBase + _types) + 1; + + for ( int nTypes = *(sal_uInt32 *)(_codeBase + _types); nTypes--; ) + { + delete (ExceptionType *) (_codeBase + pTypes[nTypes]); + } + ::rtl_freeMemory( (void*)(_codeBase +_types) ); + ::rtl_freeMemory( _code ); + + ::typelib_typedescription_release( _pTD ); +} + +ExceptionInfos::ExceptionInfos() throw () +{ +} + +ExceptionInfos::~ExceptionInfos() throw () +{ +#if OSL_DEBUG_LEVEL > 1 + OSL_TRACE( "> freeing exception infos... <\n" ); +#endif + + MutexGuard aGuard( _aMutex ); + for ( t_string2PtrMap::const_iterator iPos( _allRaiseInfos.begin() ); + iPos != _allRaiseInfos.end(); ++iPos ) + { + delete (RaiseInfo *)iPos->second; + } +} + +RaiseInfo * ExceptionInfos::getRaiseInfo( typelib_TypeDescription * pTD ) throw () +{ + static ExceptionInfos * s_pInfos = 0; + if (! s_pInfos) + { + MutexGuard aGuard( Mutex::getGlobalMutex() ); + if (! s_pInfos) + { + SYSTEM_INFO systemInfo; + GetSystemInfo( &systemInfo ); + allocationGranularity = systemInfo.dwAllocationGranularity; + +#ifdef LEAK_STATIC_DATA + s_pInfos = new ExceptionInfos(); +#else + static ExceptionInfos s_allExceptionInfos; + s_pInfos = &s_allExceptionInfos; +#endif + } + } + + OSL_ASSERT( pTD && + (pTD->eTypeClass == typelib_TypeClass_STRUCT || + pTD->eTypeClass == typelib_TypeClass_EXCEPTION) ); + + RaiseInfo * pRaiseInfo; + + OUString const & rTypeName = *reinterpret_cast< OUString * >( &pTD->pTypeName ); + MutexGuard aGuard( s_pInfos->_aMutex ); + t_string2PtrMap::const_iterator const iFind( + s_pInfos->_allRaiseInfos.find( rTypeName ) ); + if (iFind == s_pInfos->_allRaiseInfos.end()) + { + pRaiseInfo = new RaiseInfo( pTD ); + + // Put into map + pair< t_string2PtrMap::iterator, bool > insertion( + s_pInfos->_allRaiseInfos.insert( t_string2PtrMap::value_type( rTypeName, (void *)pRaiseInfo ) ) ); + OSL_ENSURE( insertion.second, "### raise info insertion failed?!" ); + } + else + { + // Reuse existing info + pRaiseInfo = (RaiseInfo *)iFind->second; + } + + return pRaiseInfo; +} + +type_info * mscx_getRTTI( + OUString const & rUNOname ) +{ + static RTTInfos * s_pRTTIs = 0; + if (! s_pRTTIs) + { + MutexGuard aGuard( Mutex::getGlobalMutex() ); + if (! s_pRTTIs) + { +#ifdef LEAK_STATIC_DATA + s_pRTTIs = new RTTInfos(); +#else + static RTTInfos s_aRTTIs; + s_pRTTIs = &s_aRTTIs; +#endif + } + } + return s_pRTTIs->getRTTI( rUNOname ); +} + +void mscx_raiseException( + uno_Any * pUnoExc, + uno_Mapping * pUno2Cpp ) +{ + // no ctor/dtor in here: this leads to dtors called twice upon RaiseException()! + // thus this obj file will be compiled without opt, so no inlining of + // ExceptionInfos::getRaiseInfo() + + // construct cpp exception object + typelib_TypeDescription * pTD = NULL; + TYPELIB_DANGER_GET( &pTD, pUnoExc->pType ); + + void * pCppExc = alloca( pTD->nSize ); + ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTD, pUno2Cpp ); + + ULONG_PTR arFilterArgs[4]; + arFilterArgs[0] = MSVC_magic_number; + arFilterArgs[1] = (ULONG_PTR)pCppExc; + arFilterArgs[2] = (ULONG_PTR)ExceptionInfos::getRaiseInfo( pTD ); + arFilterArgs[3] = ((RaiseInfo *)arFilterArgs[2])->_codeBase; + + // Destruct uno exception + ::uno_any_destruct( pUnoExc, 0 ); + TYPELIB_DANGER_RELEASE( pTD ); + + // last point to release anything not affected by stack unwinding + RaiseException( MSVC_ExceptionCode, EXCEPTION_NONCONTINUABLE, 3, arFilterArgs ); +} + +int mscx_filterCppException( + EXCEPTION_POINTERS * pPointers, + uno_Any * pUnoExc, + uno_Mapping * pCpp2Uno ) +{ + if (pPointers == 0) + return EXCEPTION_CONTINUE_SEARCH; + + EXCEPTION_RECORD * pRecord = pPointers->ExceptionRecord; + + // Handle only C++ exceptions: + if (pRecord == 0 || pRecord->ExceptionCode != MSVC_ExceptionCode) + return EXCEPTION_CONTINUE_SEARCH; + + bool rethrow = __CxxDetectRethrow( &pRecord ); + OSL_ASSERT( pRecord == pPointers->ExceptionRecord ); + + if (rethrow && pRecord == pPointers->ExceptionRecord) + { + // Hack to get msvcrt internal _curexception field: + pRecord = *reinterpret_cast< EXCEPTION_RECORD ** >( + reinterpret_cast< char * >( __pxcptinfoptrs() ) + + // As long as we don't demand MSVCR source as build prerequisite, + // we have to code those offsets here. + // + // MSVS9/crt/src/mtdll.h: + // offsetof (_tiddata, _curexception) - + // offsetof (_tiddata, _tpxcptinfoptrs): +#if _MSC_VER < 1500 + error, this compiler version is not supported +#elif _MSC_VER < 1600 + 0x48 // msvcr90.dll +#else + error, please find value for this compiler version +#endif + ); + } + + // Rethrow: handle only C++ exceptions: + if (pRecord == 0 || pRecord->ExceptionCode != MSVC_ExceptionCode) + return EXCEPTION_CONTINUE_SEARCH; + + if (pRecord->NumberParameters == 4 && + pRecord->ExceptionInformation[0] == MSVC_magic_number && + pRecord->ExceptionInformation[1] != 0 && + pRecord->ExceptionInformation[2] != 0 && + pRecord->ExceptionInformation[3] != 0) + { + // ExceptionInformation[1] is the address of the thrown object + // (or the address of a pointer to it, in most cases when it + // is a C++ class, obviously). + + // [2] is the throwinfo pointer + + // [3] is the image base address which is added the 32-bit + // rva_t fields in throwinfo to get actual 64-bit addresses + + void * types = + (void *) (pRecord->ExceptionInformation[3] + + ((RaiseInfo *)pRecord->ExceptionInformation[2])->_types); + + if (types != 0 && *(DWORD *)types > 0) + { + DWORD pType = *((DWORD *)types + 1); + if (pType != 0 && + ((ExceptionType *)(pRecord->ExceptionInformation[3]+pType))->_pTypeInfo != 0) + { + OUString aRTTIname( + OStringToOUString( + reinterpret_cast< __type_info * >( + ((ExceptionType *)(pRecord->ExceptionInformation[3]+pType))->_pTypeInfo )->_m_d_name, + RTL_TEXTENCODING_ASCII_US ) ); + OUString aUNOname( toUNOname( aRTTIname ) ); + + typelib_TypeDescription * pExcTD = 0; + typelib_typedescription_getByName( + &pExcTD, aUNOname.pData ); + if (pExcTD == NULL) + { + OUStringBuffer buf; + buf.appendAscii( + RTL_CONSTASCII_STRINGPARAM( + "[mscx_uno bridge error] UNO type of " + "C++ exception unknown: \"") ); + buf.append( aUNOname ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( + "\", RTTI-name=\"") ); + buf.append( aRTTIname ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\"!") ); + RuntimeException exc( + buf.makeStringAndClear(), Reference< XInterface >() ); + uno_type_any_constructAndConvert( + pUnoExc, &exc, + ::getCppuType( &exc ).getTypeLibType(), pCpp2Uno ); +#if _MSC_VER < 1400 // msvcr80.dll cleans up, different from former msvcrs + // if (! rethrow): + // though this unknown exception leaks now, no user-defined + // exception is ever thrown thru the binary C-UNO dispatcher + // call stack. +#endif + } + else + { + // construct uno exception any + uno_any_constructAndConvert( + pUnoExc, (void *) pRecord->ExceptionInformation[1], + pExcTD, pCpp2Uno ); +#if _MSC_VER < 1400 // msvcr80.dll cleans up, different from former msvcrs + if (! rethrow) + { + uno_destructData( + (void *) pRecord->ExceptionInformation[1], + pExcTD, cpp_release ); + } +#endif + typelib_typedescription_release( pExcTD ); + } + + return EXCEPTION_EXECUTE_HANDLER; + } + } + } + // though this unknown exception leaks now, no user-defined exception + // is ever thrown thru the binary C-UNO dispatcher call stack. + RuntimeException exc( + OUString( RTL_CONSTASCII_USTRINGPARAM( + "[mscx_uno bridge error] unexpected " + "C++ exception occurred!") ), + Reference< XInterface >() ); + uno_type_any_constructAndConvert( + pUnoExc, &exc, ::getCppuType( &exc ).getTypeLibType(), pCpp2Uno ); + return EXCEPTION_EXECUTE_HANDLER; +} + +} + +#pragma pack(pop) + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/makefile.mk b/bridges/source/cpp_uno/msvc_win32_x86-64/makefile.mk new file mode 100644 index 000000000000..7f73ebe4bba2 --- /dev/null +++ b/bridges/source/cpp_uno/msvc_win32_x86-64/makefile.mk @@ -0,0 +1,83 @@ +#************************************************************************* +# +# 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=mscx_uno +LIBTARGET=no +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +# --- Files -------------------------------------------------------- +.IF "$(COM)$(CPU)" == "MSCX" + +.IF "$(debug)" != "" +CFLAGS += -Ob0 +.ENDIF + +.IF "$(cppu_no_leak)" == "" +.IF "$(bndchk)" == "" +CFLAGS += -DLEAK_STATIC_DATA +.ENDIF +.ENDIF + + +SLOFILES= \ + $(SLO)$/cpp2uno.obj \ + $(SLO)$/uno2cpp.obj \ + $(SLO)$/dllinit.obj \ + $(SLO)$/except.obj \ + $(SLO)$/call.obj + +NOOPTFILES= \ + $(SLO)$/except.obj + +SHL1TARGET= $(TARGET) + +SHL1DEF=$(MISC)$/$(SHL1TARGET).def +SHL1IMPLIB=i$(TARGET) +SHL1VERSIONMAP=..$/..$/bridge_exports.map +SHL1RPATH=URELIB + +SHL1OBJS = $(SLOFILES) +SHL1LIBS = $(SLB)$/cpp_uno_shared.lib + +SHL1STDLIBS= \ + $(CPPULIB) \ + $(SALLIB) + +DEF1NAME=$(SHL1TARGET) + +.ENDIF + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/mscx.hxx b/bridges/source/cpp_uno/msvc_win32_x86-64/mscx.hxx new file mode 100644 index 000000000000..044bd4bb1316 --- /dev/null +++ b/bridges/source/cpp_uno/msvc_win32_x86-64/mscx.hxx @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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. + * + ************************************************************************/ + +#pragma warning(push, 1) +#include <windows.h> +#pragma warning(pop) + +#include "rtl/ustring.hxx" + + +class type_info; +typedef struct _uno_Any uno_Any; +typedef struct _uno_Mapping uno_Mapping; + +namespace CPPU_CURRENT_NAMESPACE +{ + +const DWORD MSVC_ExceptionCode = 0xe06d7363; +const long MSVC_magic_number = 0x19930520L; + +typedef enum { REGPARAM_INT, REGPARAM_FLT } RegParamKind; + + +//============================================================================== +type_info * mscx_getRTTI( ::rtl::OUString const & rUNOname ); + +//============================================================================== +int mscx_filterCppException( + EXCEPTION_POINTERS * pPointers, uno_Any * pUnoExc, uno_Mapping * pCpp2Uno ); + +//============================================================================== +void mscx_raiseException( + uno_Any * pUnoExc, uno_Mapping * pUno2Cpp ); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/uno2cpp.cxx b/bridges/source/cpp_uno/msvc_win32_x86-64/uno2cpp.cxx new file mode 100644 index 000000000000..7271aa510847 --- /dev/null +++ b/bridges/source/cpp_uno/msvc_win32_x86-64/uno2cpp.cxx @@ -0,0 +1,450 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 <malloc.h> + +#include <com/sun/star/uno/genfunc.hxx> +#include <uno/data.h> + +#include "bridges/cpp_uno/shared/bridge.hxx" +#include "bridges/cpp_uno/shared/types.hxx" +#include "bridges/cpp_uno/shared/unointerfaceproxy.hxx" +#include "bridges/cpp_uno/shared/vtables.hxx" + +#include "mscx.hxx" + +#if OSL_DEBUG_LEVEL > 1 +#include <stdio.h> +#endif + +using namespace ::rtl; +using namespace ::com::sun::star::uno; + +namespace +{ + +static bool 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 ) throw () +{ + const int MAXPARAMS = 20; + + if ( nParams > MAXPARAMS ) + { + // We have a hard limit on the number of parameters so that we + // don't need any assembler code here but can call the + // function using normal C++. + + return false; + } + + // Table with this pointer, optional complex return value ptr, and the parameters + union { + sal_Int64 i; + void *p; + double d; + } aCppParams[MAXPARAMS+2], uRetVal; + int nCppParamIndex = 0; + + // Return type + typelib_TypeDescription * pReturnTD = NULL; + TYPELIB_DANGER_GET( &pReturnTD, pReturnTypeRef ); + OSL_ENSURE( pReturnTD, "### expected return type description!" ); + + // 'this' + void * pAdjustedThisPtr = (void **)( pThis->getCppI() ) + aVtableSlot.offset; + aCppParams[nCppParamIndex++].p = pAdjustedThisPtr; + + bool bSimpleReturn = true; + if ( pReturnTD ) + { + if ( !bridges::cpp_uno::shared::isSimpleType( pReturnTD ) ) + { + // Complex return via ptr + bSimpleReturn = false; + aCppParams[nCppParamIndex++].p = + bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTD )? + alloca( pReturnTD->nSize ) : pUnoReturn; + } + } + + // Indexes of values this have to be converted (interface conversion C++<=>UNO) + int pTempCppIndexes[MAXPARAMS]; + int pTempIndexes[MAXPARAMS]; + int nTempIndexes = 0; + + // Type descriptions for reconversions + typelib_TypeDescription *pTempParamTypeDescr[MAXPARAMS]; + + for ( int nPos = 0; nPos < nParams; ++nPos, ++nCppParamIndex ) + { + const typelib_MethodParameter & rParam = pParams[nPos]; + + typelib_TypeDescription * pParamTD = NULL; + TYPELIB_DANGER_GET( &pParamTD, rParam.pTypeRef ); + + if ( !rParam.bOut && + bridges::cpp_uno::shared::isSimpleType( pParamTD ) ) + { + ::uno_copyAndConvertData( + &aCppParams[nCppParamIndex], pUnoArgs[nPos], pParamTD, + pThis->getBridge()->getUno2Cpp() ); + + // No longer needed + TYPELIB_DANGER_RELEASE( pParamTD ); + } + else // Ptr to complex value | ref + { + if ( !rParam.bIn ) // Is pure out + { + // C++ out is constructed mem, UNO out is not! + ::uno_constructData( + aCppParams[nCppParamIndex].p = alloca( pParamTD->nSize ), + pParamTD ); + + pTempCppIndexes[nTempIndexes] = nCppParamIndex; + pTempIndexes[nTempIndexes] = nPos; + + // Will be released at reconversion + pTempParamTypeDescr[nTempIndexes++] = pParamTD; + + } + // Is in/inout + else if ( bridges::cpp_uno::shared::relatesToInterfaceType( pParamTD ) ) + { + ::uno_copyAndConvertData( + aCppParams[nCppParamIndex].p = alloca( pParamTD->nSize ), + pUnoArgs[nPos], pParamTD, + pThis->getBridge()->getUno2Cpp() ); + + pTempCppIndexes[nTempIndexes] = nCppParamIndex; + pTempIndexes[nTempIndexes] = nPos; + + // Will be released at reconversion + pTempParamTypeDescr[nTempIndexes++] = pParamTD; + } + else // direct way + { + aCppParams[nCppParamIndex].p = pUnoArgs[nPos]; + + // No longer needed + TYPELIB_DANGER_RELEASE( pParamTD ); + } + } + } + + __try + { + // The first real parameter is always 'this'. + + // The Windows x64 calling convention is very regular and + // elegant (even if perhaps then slightly slower than the + // Linux x64 one): The first four parameters, never more, are + // passed in registers, as long as they are a qword in size + // or less. (If larger, a pointer to a temp copy is passed, so + // it's equivalent anyway.) Floating point values are passed + // in XMM0..3 registers, others in RCX, RDX, R8, R9. + + // Now, the nice thing for us is that when calling varargs + // functions, floating-point parameters among the four first + // ones are always passed *both* in an XMM and integer + // register. So we don't need to bother here calling the + // method different ways depending on what types of parameters + // it actually expects. We just pretend parameters 3..4 are + // doubles, and they will be passed both in XMM and integer + // registers, and the callee will find them where it + // expects. (The callee is not actually varargs, of course.) + + sal_Int64 (*pIMethod)(sal_Int64, ...) = + (sal_Int64 (*)(sal_Int64, ...)) + (*((sal_uInt64 **)pAdjustedThisPtr))[aVtableSlot.index]; + + double (*pFMethod)(sal_Int64, ...) = + (double (*)(sal_Int64, ...)) + (*((sal_uInt64 **)pAdjustedThisPtr))[aVtableSlot.index]; + + // Pass parameters 2..4 as if it was a floating-point value so + // that it gets put in both XMM and integer registers per the + // calling convention. It doesn't matter if it actually is a + // fp or not. + + if ( pReturnTD && + (pReturnTD->eTypeClass == typelib_TypeClass_FLOAT || + pReturnTD->eTypeClass == typelib_TypeClass_DOUBLE) ) + uRetVal.d = + pFMethod (aCppParams[0].i, aCppParams[1].d, aCppParams[2].d, aCppParams[3].d, + aCppParams[4].i, aCppParams[5].i, aCppParams[6].i, aCppParams[7].i, + aCppParams[8].i, aCppParams[9].i, aCppParams[10].i, aCppParams[11].i, + aCppParams[12].i, aCppParams[13].i, aCppParams[14].i, aCppParams[15].i, + aCppParams[16].i, aCppParams[17].i, aCppParams[18].i, aCppParams[19].i ); + else + uRetVal.i = + pIMethod (aCppParams[0].i, aCppParams[1].d, aCppParams[2].d, aCppParams[3].d, + aCppParams[4].i, aCppParams[5].i, aCppParams[6].i, aCppParams[7].i, + aCppParams[8].i, aCppParams[9].i, aCppParams[10].i, aCppParams[11].i, + aCppParams[12].i, aCppParams[13].i, aCppParams[14].i, aCppParams[15].i, + aCppParams[16].i, aCppParams[17].i, aCppParams[18].i, aCppParams[19].i ); + } + __except (CPPU_CURRENT_NAMESPACE::mscx_filterCppException( + GetExceptionInformation(), + *ppUnoExc, pThis->getBridge()->getCpp2Uno() )) + { + // *ppUnoExc was constructed by filter function. + // Temporary params + while ( nTempIndexes-- ) + { + int nCppIndex = pTempCppIndexes[nTempIndexes]; + // Destroy temp C++ param => C++: every param was constructed + ::uno_destructData( + aCppParams[nCppIndex].p, pTempParamTypeDescr[nTempIndexes], + cpp_release ); + TYPELIB_DANGER_RELEASE( pTempParamTypeDescr[nTempIndexes] ); + } + // Return type + if ( pReturnTD ) + TYPELIB_DANGER_RELEASE( pReturnTD ); + + // End here + return true; + } + + // No exception occurred + *ppUnoExc = NULL; + + // Reconvert temporary params + while ( nTempIndexes-- ) + { + int nCppIndex = pTempCppIndexes[nTempIndexes]; + int nIndex = pTempIndexes[nTempIndexes]; + typelib_TypeDescription * pParamTD = + pTempParamTypeDescr[nTempIndexes]; + + if ( pParams[nIndex].bIn ) + { + if ( pParams[nIndex].bOut ) // Inout + { + ::uno_destructData( + pUnoArgs[nIndex], pParamTD, 0 ); // Destroy UNO value + ::uno_copyAndConvertData( + pUnoArgs[nIndex], aCppParams[nCppIndex].p, pParamTD, + pThis->getBridge()->getCpp2Uno() ); + } + } + else // Pure out + { + ::uno_copyAndConvertData( + pUnoArgs[nIndex], aCppParams[nCppIndex].p, pParamTD, + pThis->getBridge()->getCpp2Uno() ); + } + + // Destroy temp C++ param => C++: every param was constructed + ::uno_destructData( + aCppParams[nCppIndex].p, pParamTD, cpp_release ); + + TYPELIB_DANGER_RELEASE( pParamTD ); + } + + // Return value + if ( !bSimpleReturn ) + { + ::uno_copyAndConvertData( + pUnoReturn, uRetVal.p, pReturnTD, + pThis->getBridge()->getCpp2Uno() ); + ::uno_destructData( + aCppParams[1].p, pReturnTD, cpp_release ); + } + else if ( pUnoReturn ) + *(sal_Int64*)pUnoReturn = uRetVal.i; + + if ( pReturnTD ) + TYPELIB_DANGER_RELEASE( pReturnTD ); + + return true; +} + +} + +namespace bridges { namespace cpp_uno { namespace shared { + +void unoInterfaceProxyDispatch( + uno_Interface * pUnoI, + const typelib_TypeDescription * pMemberTD, + void * pReturn, + void * pArgs[], + uno_Any ** ppException ) +{ + // is my surrogate + 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 (pMemberTD->eTypeClass) + { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + { +#if OSL_DEBUG_LEVEL > 0 + // determine vtable call index + sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberTD)->nPosition; + OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### member pos out of range!" ); +#endif + VtableSlot aVtableSlot( + getVtableSlot( + reinterpret_cast< + typelib_InterfaceAttributeTypeDescription const * >( + pMemberTD))); + if ( pReturn ) + { + // Is GET + cpp_call( + pThis, aVtableSlot, + ((typelib_InterfaceAttributeTypeDescription *)pMemberTD)->pAttributeTypeRef, + 0, NULL, // no params + pReturn, pArgs, ppException ); + } + else + { + // Is SET + typelib_MethodParameter aParam; + aParam.pTypeRef = + ((typelib_InterfaceAttributeTypeDescription *)pMemberTD)->pAttributeTypeRef; + aParam.bIn = sal_True; + aParam.bOut = sal_False; + + typelib_TypeDescriptionReference * pReturnTypeRef = NULL; + OUString aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") ); + typelib_typedescriptionreference_new( + &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData ); + + aVtableSlot.index += 1; // get, then set method + 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 + // determine vtable call index + sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberTD)->nPosition; + OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### member pos out of range!" ); +#endif + VtableSlot aVtableSlot( + getVtableSlot( + reinterpret_cast< + typelib_InterfaceMethodTypeDescription const * >( + pMemberTD))); + + switch (aVtableSlot.index) + { + // Standard calls + case 1: // Acquire UNO interface + (*pUnoI->acquire)( pUnoI ); + *ppException = 0; + break; + case 2: // Release UNO interface + (*pUnoI->release)( pUnoI ); + *ppException = 0; + break; + case 0: // queryInterface() opt + { + typelib_TypeDescription * pTD = NULL; + TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() ); + + if ( pTD ) + { + uno_Interface * pInterface = NULL; + (*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 ); + } + } // Else perform queryInterface() + default: + if ( ! cpp_call( + pThis, aVtableSlot, + ((typelib_InterfaceMethodTypeDescription *)pMemberTD)->pReturnTypeRef, + ((typelib_InterfaceMethodTypeDescription *)pMemberTD)->nParams, + ((typelib_InterfaceMethodTypeDescription *)pMemberTD)->pParams, + pReturn, pArgs, ppException ) ) + { + RuntimeException aExc( + OUString( RTL_CONSTASCII_USTRINGPARAM("Too many parameters!") ), + Reference< XInterface >() ); + + Type const & rExcType = ::getCppuType( &aExc ); + ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 ); + } + } + break; + } + default: + { + RuntimeException aExc( + OUString( RTL_CONSTASCII_USTRINGPARAM("Illegal member type description!") ), + Reference< XInterface >() ); + + Type const & rExcType = ::getCppuType( &aExc ); + // Binary identical null reference (whatever that comment means...) + ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 ); + } + } +} + +} } } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |