1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_bridges.hxx" 30 31 #include <malloc.h> 32 #include <sal/alloca.h> 33 34 #include <com/sun/star/uno/genfunc.hxx> 35 #include "com/sun/star/uno/RuntimeException.hpp" 36 #include <uno/data.h> 37 38 #include "bridges/cpp_uno/shared/bridge.hxx" 39 #include "bridges/cpp_uno/shared/types.hxx" 40 #include "bridges/cpp_uno/shared/unointerfaceproxy.hxx" 41 #include "bridges/cpp_uno/shared/vtables.hxx" 42 43 #include "share.hxx" 44 45 using namespace ::rtl; 46 using namespace ::com::sun::star::uno; 47 48 namespace 49 { 50 51 //================================================================================================== 52 static void callVirtualMethod( 53 void * pAdjustedThisPtr, 54 sal_Int32 nVtableIndex, 55 void * pRegisterReturn, 56 typelib_TypeClass eReturnType, 57 sal_Int32 * pStackLongs, 58 sal_Int32 nStackLongs ) 59 { 60 // parameter list is mixed list of * and values 61 // reference parameters are pointers 62 63 OSL_ENSURE( pStackLongs && pAdjustedThisPtr, "### null ptr!" ); 64 OSL_ENSURE( (sizeof(void *) == 4) && (sizeof(sal_Int32) == 4), "### unexpected size of int!" ); 65 OSL_ENSURE( nStackLongs && pStackLongs, "### no stack in callVirtualMethod !" ); 66 67 // never called 68 if (! pAdjustedThisPtr) CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything("xxx"); // address something 69 70 volatile long edx = 0, eax = 0; // for register returns 71 void * stackptr; 72 asm volatile ( 73 "mov %%esp, %6\n\t" 74 // copy values 75 "mov %0, %%eax\n\t" 76 "mov %%eax, %%edx\n\t" 77 "dec %%edx\n\t" 78 "shl $2, %%edx\n\t" 79 "add %1, %%edx\n" 80 "Lcopy:\n\t" 81 "pushl 0(%%edx)\n\t" 82 "sub $4, %%edx\n\t" 83 "dec %%eax\n\t" 84 "jne Lcopy\n\t" 85 // do the actual call 86 "mov %2, %%edx\n\t" 87 "mov 0(%%edx), %%edx\n\t" 88 "mov %3, %%eax\n\t" 89 "shl $2, %%eax\n\t" 90 "add %%eax, %%edx\n\t" 91 "mov 0(%%edx), %%edx\n\t" 92 "call *%%edx\n\t" 93 // save return registers 94 "mov %%eax, %4\n\t" 95 "mov %%edx, %5\n\t" 96 // cleanup stack 97 "mov %6, %%esp\n\t" 98 : 99 : "m"(nStackLongs), "m"(pStackLongs), "m"(pAdjustedThisPtr), 100 "m"(nVtableIndex), "m"(eax), "m"(edx), "m"(stackptr) 101 : "eax", "edx" ); 102 switch( eReturnType ) 103 { 104 case typelib_TypeClass_HYPER: 105 case typelib_TypeClass_UNSIGNED_HYPER: 106 ((long*)pRegisterReturn)[1] = edx; 107 case typelib_TypeClass_LONG: 108 case typelib_TypeClass_UNSIGNED_LONG: 109 case typelib_TypeClass_CHAR: 110 case typelib_TypeClass_ENUM: 111 ((long*)pRegisterReturn)[0] = eax; 112 break; 113 case typelib_TypeClass_SHORT: 114 case typelib_TypeClass_UNSIGNED_SHORT: 115 *(unsigned short*)pRegisterReturn = eax; 116 break; 117 case typelib_TypeClass_BOOLEAN: 118 case typelib_TypeClass_BYTE: 119 *(unsigned char*)pRegisterReturn = eax; 120 break; 121 case typelib_TypeClass_FLOAT: 122 asm ( "fstps %0" : : "m"(*(char *)pRegisterReturn) ); 123 break; 124 case typelib_TypeClass_DOUBLE: 125 asm ( "fstpl %0\n\t" : : "m"(*(char *)pRegisterReturn) ); 126 break; 127 } 128 } 129 130 //================================================================================================== 131 static void cpp_call( 132 bridges::cpp_uno::shared::UnoInterfaceProxy * pThis, 133 bridges::cpp_uno::shared::VtableSlot aVtableSlot, 134 typelib_TypeDescriptionReference * pReturnTypeRef, 135 sal_Int32 nParams, typelib_MethodParameter * pParams, 136 void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc ) 137 { 138 // max space for: [complex ret ptr], values|ptr ... 139 char * pCppStack = 140 (char *)alloca( sizeof(sal_Int32) + ((nParams+2) * sizeof(sal_Int64)) ); 141 char * pCppStackStart = pCppStack; 142 143 // return 144 typelib_TypeDescription * pReturnTypeDescr = 0; 145 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef ); 146 OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" ); 147 148 void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion 149 150 if (pReturnTypeDescr) 151 { 152 if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr )) 153 { 154 pCppReturn = pUnoReturn; // direct way for simple types 155 } 156 else 157 { 158 // complex return via ptr 159 pCppReturn = *(void **)pCppStack 160 = (bridges::cpp_uno::shared::relatesToInterfaceType( 161 pReturnTypeDescr ) 162 ? alloca( pReturnTypeDescr->nSize ) 163 : pUnoReturn); // direct way 164 pCppStack += sizeof(void *); 165 } 166 } 167 // push this 168 void * pAdjustedThisPtr = reinterpret_cast< void ** >(pThis->getCppI()) 169 + aVtableSlot.offset; 170 *(void**)pCppStack = pAdjustedThisPtr; 171 pCppStack += sizeof( void* ); 172 173 // stack space 174 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" ); 175 // args 176 void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams ); 177 // indizes of values this have to be converted (interface conversion cpp<=>uno) 178 sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams); 179 // type descriptions for reconversions 180 typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams)); 181 182 sal_Int32 nTempIndizes = 0; 183 184 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) 185 { 186 const typelib_MethodParameter & rParam = pParams[nPos]; 187 typelib_TypeDescription * pParamTypeDescr = 0; 188 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef ); 189 190 if (!rParam.bOut 191 && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr )) 192 { 193 uno_copyAndConvertData( pCppArgs[nPos] = pCppStack, pUnoArgs[nPos], pParamTypeDescr, 194 pThis->getBridge()->getUno2Cpp() ); 195 196 switch (pParamTypeDescr->eTypeClass) 197 { 198 case typelib_TypeClass_HYPER: 199 case typelib_TypeClass_UNSIGNED_HYPER: 200 case typelib_TypeClass_DOUBLE: 201 pCppStack += sizeof(sal_Int32); // extra long 202 } 203 // no longer needed 204 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 205 } 206 else // ptr to complex value | ref 207 { 208 if (! rParam.bIn) // is pure out 209 { 210 // cpp out is constructed mem, uno out is not! 211 uno_constructData( 212 *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ), 213 pParamTypeDescr ); 214 pTempIndizes[nTempIndizes] = nPos; // default constructed for cpp call 215 // will be released at reconversion 216 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 217 } 218 // is in/inout 219 else if (bridges::cpp_uno::shared::relatesToInterfaceType( 220 pParamTypeDescr )) 221 { 222 uno_copyAndConvertData( 223 *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ), 224 pUnoArgs[nPos], pParamTypeDescr, 225 pThis->getBridge()->getUno2Cpp() ); 226 227 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted 228 // will be released at reconversion 229 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 230 } 231 else // direct way 232 { 233 *(void **)pCppStack = pCppArgs[nPos] = pUnoArgs[nPos]; 234 // no longer needed 235 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 236 } 237 } 238 pCppStack += sizeof(sal_Int32); // standard parameter length 239 } 240 241 try 242 { 243 OSL_ENSURE( !( (pCppStack - pCppStackStart ) & 3), "UNALIGNED STACK !!! (Please DO panic)" ); 244 callVirtualMethod( 245 pAdjustedThisPtr, aVtableSlot.index, 246 pCppReturn, pReturnTypeDescr->eTypeClass, 247 (sal_Int32 *)pCppStackStart, (pCppStack - pCppStackStart) / sizeof(sal_Int32) ); 248 // NO exception occured... 249 *ppUnoExc = 0; 250 251 // reconvert temporary params 252 for ( ; nTempIndizes--; ) 253 { 254 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 255 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes]; 256 257 if (pParams[nIndex].bIn) 258 { 259 if (pParams[nIndex].bOut) // inout 260 { 261 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value 262 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr, 263 pThis->getBridge()->getCpp2Uno() ); 264 } 265 } 266 else // pure out 267 { 268 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr, 269 pThis->getBridge()->getCpp2Uno() ); 270 } 271 // destroy temp cpp param => cpp: every param was constructed 272 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release ); 273 274 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 275 } 276 // return value 277 if (pCppReturn && pUnoReturn != pCppReturn) 278 { 279 uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr, 280 pThis->getBridge()->getCpp2Uno() ); 281 uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release ); 282 } 283 } 284 catch (...) 285 { 286 // fill uno exception 287 fillUnoException( CPPU_CURRENT_NAMESPACE::__cxa_get_globals()->caughtExceptions, *ppUnoExc, pThis->getBridge()->getCpp2Uno() ); 288 289 // temporary params 290 for ( ; nTempIndizes--; ) 291 { 292 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 293 // destroy temp cpp param => cpp: every param was constructed 294 uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], cpp_release ); 295 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] ); 296 } 297 // return type 298 if (pReturnTypeDescr) 299 TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); 300 } 301 } 302 303 } 304 305 namespace bridges { namespace cpp_uno { namespace shared { 306 307 void unoInterfaceProxyDispatch( 308 uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr, 309 void * pReturn, void * pArgs[], uno_Any ** ppException ) 310 { 311 // is my surrogate 312 bridges::cpp_uno::shared::UnoInterfaceProxy * pThis 313 = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI); 314 typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr; 315 316 switch (pMemberDescr->eTypeClass) 317 { 318 case typelib_TypeClass_INTERFACE_ATTRIBUTE: 319 { 320 VtableSlot aVtableSlot( 321 getVtableSlot( 322 reinterpret_cast< 323 typelib_InterfaceAttributeTypeDescription const * >( 324 pMemberDescr))); 325 if (pReturn) 326 { 327 // dependent dispatch 328 cpp_call( 329 pThis, aVtableSlot, 330 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef, 331 0, 0, // no params 332 pReturn, pArgs, ppException ); 333 } 334 else 335 { 336 // is SET 337 typelib_MethodParameter aParam; 338 aParam.pTypeRef = 339 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef; 340 aParam.bIn = sal_True; 341 aParam.bOut = sal_False; 342 343 typelib_TypeDescriptionReference * pReturnTypeRef = 0; 344 OUString aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") ); 345 typelib_typedescriptionreference_new( 346 &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData ); 347 348 // dependent dispatch 349 aVtableSlot.index += 1; // get, then set method 350 cpp_call( 351 pThis, aVtableSlot, 352 pReturnTypeRef, 353 1, &aParam, 354 pReturn, pArgs, ppException ); 355 356 typelib_typedescriptionreference_release( pReturnTypeRef ); 357 } 358 359 break; 360 } 361 case typelib_TypeClass_INTERFACE_METHOD: 362 { 363 VtableSlot aVtableSlot( 364 getVtableSlot( 365 reinterpret_cast< 366 typelib_InterfaceMethodTypeDescription const * >( 367 pMemberDescr))); 368 switch (aVtableSlot.index) 369 { 370 // standard calls 371 case 1: // acquire uno interface 372 (*pUnoI->acquire)( pUnoI ); 373 *ppException = 0; 374 break; 375 case 2: // release uno interface 376 (*pUnoI->release)( pUnoI ); 377 *ppException = 0; 378 break; 379 case 0: // queryInterface() opt 380 { 381 typelib_TypeDescription * pTD = 0; 382 TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() ); 383 if (pTD) 384 { 385 uno_Interface * pInterface = 0; 386 (*pThis->pBridge->getUnoEnv()->getRegisteredInterface)( 387 pThis->pBridge->getUnoEnv(), 388 (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD ); 389 390 if (pInterface) 391 { 392 ::uno_any_construct( 393 reinterpret_cast< uno_Any * >( pReturn ), 394 &pInterface, pTD, 0 ); 395 (*pInterface->release)( pInterface ); 396 TYPELIB_DANGER_RELEASE( pTD ); 397 *ppException = 0; 398 break; 399 } 400 TYPELIB_DANGER_RELEASE( pTD ); 401 } 402 } // else perform queryInterface() 403 default: 404 // dependent dispatch 405 cpp_call( 406 pThis, aVtableSlot, 407 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef, 408 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams, 409 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams, 410 pReturn, pArgs, ppException ); 411 } 412 break; 413 } 414 default: 415 { 416 ::com::sun::star::uno::RuntimeException aExc( 417 OUString( RTL_CONSTASCII_USTRINGPARAM("illegal member type description!") ), 418 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() ); 419 420 Type const & rExcType = ::getCppuType( &aExc ); 421 // binary identical null reference 422 ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 ); 423 } 424 } 425 } 426 427 } } } 428