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 <com/sun/star/uno/genfunc.hxx> 32 #include "com/sun/star/uno/RuntimeException.hpp" 33 #include <uno/data.h> 34 #include <sal/alloca.h> 35 36 #include "bridges/cpp_uno/shared/bridge.hxx" 37 #include "bridges/cpp_uno/shared/types.hxx" 38 #include "bridges/cpp_uno/shared/unointerfaceproxy.hxx" 39 #include "bridges/cpp_uno/shared/vtables.hxx" 40 41 #include "share.hxx" 42 #include "smallstruct.hxx" 43 44 using namespace ::rtl; 45 using namespace ::com::sun::star::uno; 46 47 namespace 48 { 49 50 //================================================================================================== 51 // The call instruction within the asm section of callVirtualMethod may throw 52 // exceptions. So that the compiler handles this correctly, it is important 53 // that (a) callVirtualMethod might call dummy_can_throw_anything (although this 54 // never happens at runtime), which in turn can throw exceptions, and (b) 55 // callVirtualMethod is not inlined at its call site (so that any exceptions are 56 // caught which are thrown from the instruction calling callVirtualMethod): 57 void callVirtualMethod( 58 void * pAdjustedThisPtr, 59 sal_Int32 nVtableIndex, 60 void * pRegisterReturn, 61 typelib_TypeDescription const * returnType, 62 sal_Int32 * pStackLongs, 63 sal_Int32 nStackLongs ) __attribute__((noinline)); 64 65 void callVirtualMethod( 66 void * pAdjustedThisPtr, 67 sal_Int32 nVtableIndex, 68 void * pRegisterReturn, 69 typelib_TypeDescription const * returnType, 70 sal_Int32 * pStackLongs, 71 sal_Int32 nStackLongs ) 72 { 73 // parameter list is mixed list of * and values 74 // reference parameters are pointers 75 76 OSL_ENSURE( pStackLongs && pAdjustedThisPtr, "### null ptr!" ); 77 OSL_ENSURE( (sizeof(void *) == 4) && (sizeof(sal_Int32) == 4), "### unexpected size of int!" ); 78 OSL_ENSURE( nStackLongs && pStackLongs, "### no stack in callVirtualMethod !" ); 79 80 // never called 81 if (! pAdjustedThisPtr) CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything("xxx"); // address something 82 83 volatile long edx = 0, eax = 0; // for register returns 84 void * stackptr; 85 asm volatile ( 86 "mov %%esp, %6\n\t" 87 // copy values 88 "mov %0, %%eax\n\t" 89 "mov %%eax, %%edx\n\t" 90 "dec %%edx\n\t" 91 "shl $2, %%edx\n\t" 92 "add %1, %%edx\n" 93 "Lcopy:\n\t" 94 "pushl 0(%%edx)\n\t" 95 "sub $4, %%edx\n\t" 96 "dec %%eax\n\t" 97 "jne Lcopy\n\t" 98 // do the actual call 99 "mov %2, %%edx\n\t" 100 "mov 0(%%edx), %%edx\n\t" 101 "mov %3, %%eax\n\t" 102 "shl $2, %%eax\n\t" 103 "add %%eax, %%edx\n\t" 104 "mov 0(%%edx), %%edx\n\t" 105 "call *%%edx\n\t" 106 // save return registers 107 "mov %%eax, %4\n\t" 108 "mov %%edx, %5\n\t" 109 // cleanup stack 110 "mov %6, %%esp\n\t" 111 : 112 : "m"(nStackLongs), "m"(pStackLongs), "m"(pAdjustedThisPtr), 113 "m"(nVtableIndex), "m"(eax), "m"(edx), "m"(stackptr) 114 : "eax", "edx" ); 115 switch( returnType->eTypeClass ) 116 { 117 case typelib_TypeClass_VOID: 118 break; 119 case typelib_TypeClass_HYPER: 120 case typelib_TypeClass_UNSIGNED_HYPER: 121 ((long*)pRegisterReturn)[1] = edx; 122 case typelib_TypeClass_LONG: 123 case typelib_TypeClass_UNSIGNED_LONG: 124 case typelib_TypeClass_CHAR: 125 case typelib_TypeClass_ENUM: 126 ((long*)pRegisterReturn)[0] = eax; 127 break; 128 case typelib_TypeClass_SHORT: 129 case typelib_TypeClass_UNSIGNED_SHORT: 130 *(unsigned short*)pRegisterReturn = eax; 131 break; 132 case typelib_TypeClass_BOOLEAN: 133 case typelib_TypeClass_BYTE: 134 *(unsigned char*)pRegisterReturn = eax; 135 break; 136 case typelib_TypeClass_FLOAT: 137 asm ( "fstps %0" : : "m"(*(char *)pRegisterReturn) ); 138 break; 139 case typelib_TypeClass_DOUBLE: 140 asm ( "fstpl %0\n\t" : : "m"(*(char *)pRegisterReturn) ); 141 break; 142 case typelib_TypeClass_STRUCT: 143 if (bridges::cpp_uno::shared::isSmallStruct(returnType)) { 144 if (returnType->nSize <= 1) { 145 *(unsigned char*)pRegisterReturn = eax; 146 } 147 else if (returnType->nSize <= 2) { 148 *(unsigned short*)pRegisterReturn = eax; 149 } 150 else if (returnType->nSize <= 8) { 151 ((long*)pRegisterReturn)[0] = eax; 152 if (returnType->nSize > 4) { 153 ((long*)pRegisterReturn)[1] = edx; 154 } 155 } 156 } 157 break; 158 default: 159 break; 160 } 161 } 162 163 //================================================================================================== 164 static void cpp_call( 165 bridges::cpp_uno::shared::UnoInterfaceProxy * pThis, 166 bridges::cpp_uno::shared::VtableSlot aVtableSlot, 167 typelib_TypeDescriptionReference * pReturnTypeRef, 168 sal_Int32 nParams, typelib_MethodParameter * pParams, 169 void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc ) 170 { 171 // max space for: [complex ret ptr], values|ptr ... 172 char * pCppStack = 173 #ifdef BROKEN_ALLOCA 174 (char *)malloc( sizeof(sal_Int32) + ((nParams+2) * sizeof(sal_Int64)) ); 175 #else 176 (char *)alloca( sizeof(sal_Int32) + ((nParams+2) * sizeof(sal_Int64)) ); 177 #endif 178 char * pCppStackStart = pCppStack; 179 180 // return 181 typelib_TypeDescription * pReturnTypeDescr = 0; 182 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef ); 183 OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" ); 184 185 void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion 186 187 if (pReturnTypeDescr) 188 { 189 if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr )) 190 { 191 pCppReturn = pUnoReturn; // direct way for simple types 192 } 193 else 194 { 195 // complex return via ptr 196 pCppReturn 197 = (bridges::cpp_uno::shared::relatesToInterfaceType( 198 pReturnTypeDescr ) 199 #ifdef BROKEN_ALLOCA 200 ? malloc( pReturnTypeDescr->nSize ) 201 #else 202 ? alloca( pReturnTypeDescr->nSize ) 203 #endif 204 : pUnoReturn); // direct way 205 if (!bridges::cpp_uno::shared::isSmallStruct(pReturnTypeDescr)) { 206 *(void **)pCppStack = pCppReturn; 207 pCppStack += sizeof(void *); 208 } 209 } 210 } 211 // push this 212 void * pAdjustedThisPtr = reinterpret_cast< void ** >(pThis->getCppI()) 213 + aVtableSlot.offset; 214 *(void**)pCppStack = pAdjustedThisPtr; 215 pCppStack += sizeof( void* ); 216 217 // stack space 218 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" ); 219 // args 220 #ifdef BROKEN_ALLOCA 221 void ** pCppArgs = (void **)malloc( 3 * sizeof(void *) * nParams ); 222 #else 223 void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams ); 224 #endif 225 // indizes of values this have to be converted (interface conversion cpp<=>uno) 226 sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams); 227 // type descriptions for reconversions 228 typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams)); 229 230 sal_Int32 nTempIndizes = 0; 231 232 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) 233 { 234 const typelib_MethodParameter & rParam = pParams[nPos]; 235 typelib_TypeDescription * pParamTypeDescr = 0; 236 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef ); 237 238 if (!rParam.bOut 239 && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr )) 240 { 241 uno_copyAndConvertData( pCppArgs[nPos] = pCppStack, pUnoArgs[nPos], pParamTypeDescr, 242 pThis->getBridge()->getUno2Cpp() ); 243 244 switch (pParamTypeDescr->eTypeClass) 245 { 246 case typelib_TypeClass_HYPER: 247 case typelib_TypeClass_UNSIGNED_HYPER: 248 case typelib_TypeClass_DOUBLE: 249 pCppStack += sizeof(sal_Int32); // extra long 250 break; 251 default: 252 break; 253 } 254 // no longer needed 255 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 256 } 257 else // ptr to complex value | ref 258 { 259 if (! rParam.bIn) // is pure out 260 { 261 // cpp out is constructed mem, uno out is not! 262 uno_constructData( 263 #ifdef BROKEN_ALLOCA 264 *(void **)pCppStack = pCppArgs[nPos] = malloc( pParamTypeDescr->nSize ), 265 #else 266 *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ), 267 #endif 268 pParamTypeDescr ); 269 pTempIndizes[nTempIndizes] = nPos; // default constructed for cpp call 270 // will be released at reconversion 271 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 272 } 273 // is in/inout 274 else if (bridges::cpp_uno::shared::relatesToInterfaceType( 275 pParamTypeDescr )) 276 { 277 uno_copyAndConvertData( 278 #ifdef BROKEN_ALLOCA 279 *(void **)pCppStack = pCppArgs[nPos] = malloc( pParamTypeDescr->nSize ), 280 #else 281 *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ), 282 #endif 283 pUnoArgs[nPos], pParamTypeDescr, 284 pThis->getBridge()->getUno2Cpp() ); 285 286 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted 287 // will be released at reconversion 288 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 289 } 290 else // direct way 291 { 292 *(void **)pCppStack = pCppArgs[nPos] = pUnoArgs[nPos]; 293 // no longer needed 294 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 295 } 296 } 297 pCppStack += sizeof(sal_Int32); // standard parameter length 298 } 299 300 try 301 { 302 OSL_ENSURE( !( (pCppStack - pCppStackStart ) & 3), "UNALIGNED STACK !!! (Please DO panic)" ); 303 callVirtualMethod( 304 pAdjustedThisPtr, aVtableSlot.index, 305 pCppReturn, pReturnTypeDescr, 306 (sal_Int32 *)pCppStackStart, (pCppStack - pCppStackStart) / sizeof(sal_Int32) ); 307 // NO exception occured... 308 *ppUnoExc = 0; 309 310 // reconvert temporary params 311 for ( ; nTempIndizes--; ) 312 { 313 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 314 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes]; 315 316 if (pParams[nIndex].bIn) 317 { 318 if (pParams[nIndex].bOut) // inout 319 { 320 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value 321 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr, 322 pThis->getBridge()->getCpp2Uno() ); 323 } 324 } 325 else // pure out 326 { 327 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr, 328 pThis->getBridge()->getCpp2Uno() ); 329 } 330 // destroy temp cpp param => cpp: every param was constructed 331 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release ); 332 #ifdef BROKEN_ALLOCA 333 free( pCppArgs[nIndex] ); 334 #endif 335 336 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 337 } 338 // return value 339 if (pCppReturn && pUnoReturn != pCppReturn) 340 { 341 uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr, 342 pThis->getBridge()->getCpp2Uno() ); 343 uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release ); 344 } 345 } 346 catch (...) 347 { 348 // fill uno exception 349 fillUnoException( CPPU_CURRENT_NAMESPACE::__cxa_get_globals()->caughtExceptions, *ppUnoExc, pThis->getBridge()->getCpp2Uno() ); 350 351 // temporary params 352 for ( ; nTempIndizes--; ) 353 { 354 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 355 // destroy temp cpp param => cpp: every param was constructed 356 uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], cpp_release ); 357 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] ); 358 #ifdef BROKEN_ALLOCA 359 free( pCppArgs[nIndex] ); 360 #endif 361 } 362 // return type 363 if (pReturnTypeDescr) 364 TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); 365 } 366 if (pCppReturn && pUnoReturn != pCppReturn) 367 { 368 #ifdef BROKEN_ALLOCA 369 free( pCppReturn ); 370 #endif 371 } 372 #ifdef BROKEN_ALLOCA 373 free( pCppStackStart ); 374 #endif 375 } 376 377 } 378 379 namespace bridges { namespace cpp_uno { namespace shared { 380 381 void unoInterfaceProxyDispatch( 382 uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr, 383 void * pReturn, void * pArgs[], uno_Any ** ppException ) 384 { 385 // is my surrogate 386 bridges::cpp_uno::shared::UnoInterfaceProxy * pThis 387 = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI); 388 389 switch (pMemberDescr->eTypeClass) 390 { 391 case typelib_TypeClass_INTERFACE_ATTRIBUTE: 392 { 393 VtableSlot aVtableSlot( 394 getVtableSlot( 395 reinterpret_cast< 396 typelib_InterfaceAttributeTypeDescription const * >( 397 pMemberDescr))); 398 if (pReturn) 399 { 400 // dependent dispatch 401 cpp_call( 402 pThis, aVtableSlot, 403 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef, 404 0, 0, // no params 405 pReturn, pArgs, ppException ); 406 } 407 else 408 { 409 // is SET 410 typelib_MethodParameter aParam; 411 aParam.pTypeRef = 412 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef; 413 aParam.bIn = sal_True; 414 aParam.bOut = sal_False; 415 416 typelib_TypeDescriptionReference * pReturnTypeRef = 0; 417 OUString aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") ); 418 typelib_typedescriptionreference_new( 419 &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData ); 420 421 // dependent dispatch 422 aVtableSlot.index += 1; // get, then set method 423 cpp_call( 424 pThis, aVtableSlot, 425 pReturnTypeRef, 426 1, &aParam, 427 pReturn, pArgs, ppException ); 428 429 typelib_typedescriptionreference_release( pReturnTypeRef ); 430 } 431 432 break; 433 } 434 case typelib_TypeClass_INTERFACE_METHOD: 435 { 436 VtableSlot aVtableSlot( 437 getVtableSlot( 438 reinterpret_cast< 439 typelib_InterfaceMethodTypeDescription const * >( 440 pMemberDescr))); 441 switch (aVtableSlot.index) 442 { 443 // standard calls 444 case 1: // acquire uno interface 445 (*pUnoI->acquire)( pUnoI ); 446 *ppException = 0; 447 break; 448 case 2: // release uno interface 449 (*pUnoI->release)( pUnoI ); 450 *ppException = 0; 451 break; 452 case 0: // queryInterface() opt 453 { 454 typelib_TypeDescription * pTD = 0; 455 TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() ); 456 if (pTD) 457 { 458 uno_Interface * pInterface = 0; 459 (*pThis->pBridge->getUnoEnv()->getRegisteredInterface)( 460 pThis->pBridge->getUnoEnv(), 461 (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD ); 462 463 if (pInterface) 464 { 465 ::uno_any_construct( 466 reinterpret_cast< uno_Any * >( pReturn ), 467 &pInterface, pTD, 0 ); 468 (*pInterface->release)( pInterface ); 469 TYPELIB_DANGER_RELEASE( pTD ); 470 *ppException = 0; 471 break; 472 } 473 TYPELIB_DANGER_RELEASE( pTD ); 474 } 475 } // else perform queryInterface() 476 default: 477 // dependent dispatch 478 cpp_call( 479 pThis, aVtableSlot, 480 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef, 481 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams, 482 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams, 483 pReturn, pArgs, ppException ); 484 } 485 break; 486 } 487 default: 488 { 489 ::com::sun::star::uno::RuntimeException aExc( 490 OUString( RTL_CONSTASCII_USTRINGPARAM("illegal member type description!") ), 491 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() ); 492 493 Type const & rExcType = ::getCppuType( &aExc ); 494 // binary identical null reference 495 ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 ); 496 } 497 } 498 } 499 500 } } } 501