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 <hash_map> 32 33 #include <sal/alloca.h> 34 #include <rtl/alloc.h> 35 #include <osl/mutex.hxx> 36 37 #include <uno/data.h> 38 #include <typelib/typedescription.hxx> 39 40 #include <bridges/cpp_uno/bridge.hxx> 41 #include <bridges/cpp_uno/type_misc.hxx> 42 43 #include "share.hxx" 44 45 46 using namespace ::osl; 47 using namespace ::rtl; 48 using namespace ::com::sun::star::uno; 49 50 namespace CPPU_CURRENT_NAMESPACE 51 { 52 53 //================================================================================================== 54 rtl_StandardModuleCount g_moduleCount = MODULE_COUNT_INIT; 55 56 //================================================================================================== 57 static typelib_TypeClass cpp2uno_call( 58 cppu_cppInterfaceProxy * pThis, 59 const typelib_TypeDescription * pMemberTypeDescr, 60 typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return 61 sal_Int32 nParams, typelib_MethodParameter * pParams, 62 void ** pCallStack, 63 sal_Int64 * pRegisterReturn /* space for register return */ ) 64 { 65 // pCallStack: ret, [return ptr], this, params 66 char * pCppStack = (char *)(pCallStack +1); 67 68 // return 69 typelib_TypeDescription * pReturnTypeDescr = 0; 70 if (pReturnTypeRef) 71 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef ); 72 73 void * pUnoReturn = 0; 74 void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need 75 76 if (pReturnTypeDescr) 77 { 78 if (cppu_isSimpleType( pReturnTypeDescr )) 79 { 80 pUnoReturn = pRegisterReturn; // direct way for simple types 81 } 82 else // complex return via ptr (pCppReturn) 83 { 84 pCppReturn = *(void **)pCppStack; 85 pCppStack += sizeof(void *); 86 87 pUnoReturn = (cppu_relatesToInterface( pReturnTypeDescr ) 88 ? alloca( pReturnTypeDescr->nSize ) 89 : pCppReturn); // direct way 90 } 91 } 92 // pop this 93 pCppStack += sizeof( void* ); 94 95 // stack space 96 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" ); 97 // parameters 98 void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams ); 99 void ** pCppArgs = pUnoArgs + nParams; 100 // indizes of values this have to be converted (interface conversion cpp<=>uno) 101 sal_Int32 * pTempIndizes = (sal_Int32 *)(pUnoArgs + (2 * nParams)); 102 // type descriptions for reconversions 103 typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams)); 104 105 sal_Int32 nTempIndizes = 0; 106 107 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) 108 { 109 const typelib_MethodParameter & rParam = pParams[nPos]; 110 typelib_TypeDescription * pParamTypeDescr = 0; 111 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef ); 112 113 if (!rParam.bOut && cppu_isSimpleType( pParamTypeDescr )) // value 114 { 115 pCppArgs[nPos] = pCppStack; 116 pUnoArgs[nPos] = pCppStack; 117 switch (pParamTypeDescr->eTypeClass) 118 { 119 case typelib_TypeClass_HYPER: 120 case typelib_TypeClass_UNSIGNED_HYPER: 121 case typelib_TypeClass_DOUBLE: 122 pCppStack += sizeof(sal_Int32); // extra long 123 } 124 // no longer needed 125 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 126 } 127 else // ptr to complex value | ref 128 { 129 pCppArgs[nPos] = *(void **)pCppStack; 130 131 if (! rParam.bIn) // is pure out 132 { 133 // uno out is unconstructed mem! 134 pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ); 135 pTempIndizes[nTempIndizes] = nPos; 136 // will be released at reconversion 137 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 138 } 139 // is in/inout 140 else if (cppu_relatesToInterface( pParamTypeDescr )) 141 { 142 uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ), 143 *(void **)pCppStack, pParamTypeDescr, 144 &pThis->pBridge->aCpp2Uno ); 145 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted 146 // will be released at reconversion 147 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 148 } 149 else // direct way 150 { 151 pUnoArgs[nPos] = *(void **)pCppStack; 152 // no longer needed 153 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 154 } 155 } 156 pCppStack += sizeof(sal_Int32); // standard parameter length 157 } 158 159 // ExceptionHolder 160 uno_Any aUnoExc; // Any will be constructed by callee 161 uno_Any * pUnoExc = &aUnoExc; 162 163 // invoke uno dispatch call 164 (*pThis->pUnoI->pDispatcher)( pThis->pUnoI, pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc ); 165 166 // in case an exception occured... 167 if (pUnoExc) 168 { 169 // destruct temporary in/inout params 170 for ( ; nTempIndizes--; ) 171 { 172 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 173 174 if (pParams[nIndex].bIn) // is in/inout => was constructed 175 uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], 0 ); 176 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] ); 177 } 178 if (pReturnTypeDescr) 179 TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); 180 181 raiseException( &aUnoExc, &pThis->pBridge->aUno2Cpp ); // has to destruct the any 182 // is here for dummy 183 return typelib_TypeClass_VOID; 184 } 185 else // else no exception occured... 186 { 187 // temporary params 188 for ( ; nTempIndizes--; ) 189 { 190 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 191 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes]; 192 193 if (pParams[nIndex].bOut) // inout/out 194 { 195 // convert and assign 196 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release ); 197 uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr, 198 &pThis->pBridge->aUno2Cpp ); 199 } 200 // destroy temp uno param 201 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); 202 203 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 204 } 205 // return 206 if (pCppReturn) // has complex return 207 { 208 if (pUnoReturn != pCppReturn) // needs reconversion 209 { 210 uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr, 211 &pThis->pBridge->aUno2Cpp ); 212 // destroy temp uno return 213 uno_destructData( pUnoReturn, pReturnTypeDescr, 0 ); 214 } 215 // complex return ptr is set to eax 216 *(void **)pRegisterReturn = pCppReturn; 217 } 218 if (pReturnTypeDescr) 219 { 220 typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass; 221 TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); 222 return eRet; 223 } 224 else 225 return typelib_TypeClass_VOID; 226 } 227 } 228 229 230 //================================================================================================== 231 static typelib_TypeClass cpp_mediate( 232 sal_Int32 nVtableCall, 233 void ** pCallStack, 234 sal_Int64 * pRegisterReturn /* space for register return */ ) 235 { 236 OSL_ENSURE( sizeof(sal_Int32)==sizeof(void *), "### unexpected!" ); 237 238 // pCallStack: ret adr, [ret *], this, params 239 // _this_ ptr is patched cppu_XInterfaceProxy object 240 cppu_cppInterfaceProxy * pCppI = NULL; 241 if( nVtableCall & 0x80000000 ) 242 { 243 nVtableCall &= 0x7fffffff; 244 pCppI = (cppu_cppInterfaceProxy *)(XInterface *)*(pCallStack +2); 245 } 246 else 247 { 248 pCppI = (cppu_cppInterfaceProxy *)(XInterface *)*(pCallStack +1); 249 } 250 251 typelib_InterfaceTypeDescription * pTypeDescr = pCppI->pTypeDescr; 252 253 OSL_ENSURE( nVtableCall < pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!" ); 254 if (nVtableCall >= pTypeDescr->nMapFunctionIndexToMemberIndex) 255 { 256 throw RuntimeException( 257 OUString::createFromAscii("illegal vtable index!"), 258 (XInterface *)pCppI ); 259 } 260 261 // determine called method 262 OSL_ENSURE( nVtableCall < pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!" ); 263 sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nVtableCall]; 264 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!" ); 265 266 TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] ); 267 268 typelib_TypeClass eRet; 269 switch (aMemberDescr.get()->eTypeClass) 270 { 271 case typelib_TypeClass_INTERFACE_ATTRIBUTE: 272 { 273 if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nVtableCall) 274 { 275 // is GET method 276 eRet = cpp2uno_call( 277 pCppI, aMemberDescr.get(), 278 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef, 279 0, 0, // no params 280 pCallStack, pRegisterReturn ); 281 } 282 else 283 { 284 // is SET method 285 typelib_MethodParameter aParam; 286 aParam.pTypeRef = 287 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef; 288 aParam.bIn = sal_True; 289 aParam.bOut = sal_False; 290 291 eRet = cpp2uno_call( 292 pCppI, aMemberDescr.get(), 293 0, // indicates void return 294 1, &aParam, 295 pCallStack, pRegisterReturn ); 296 } 297 break; 298 } 299 case typelib_TypeClass_INTERFACE_METHOD: 300 { 301 // is METHOD 302 switch (nVtableCall) 303 { 304 case 1: // acquire() 305 pCppI->acquireProxy(); // non virtual call! 306 eRet = typelib_TypeClass_VOID; 307 break; 308 case 2: // release() 309 pCppI->releaseProxy(); // non virtual call! 310 eRet = typelib_TypeClass_VOID; 311 break; 312 case 0: // queryInterface() opt 313 { 314 typelib_TypeDescription * pTD = 0; 315 TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pCallStack[3] )->getTypeLibType() ); 316 if (pTD) 317 { 318 XInterface * pInterface = 0; 319 (*pCppI->pBridge->pCppEnv->getRegisteredInterface)( 320 pCppI->pBridge->pCppEnv, 321 (void **)&pInterface, pCppI->oid.pData, (typelib_InterfaceTypeDescription *)pTD ); 322 323 if (pInterface) 324 { 325 ::uno_any_construct( 326 reinterpret_cast< uno_Any * >( pCallStack[1] ), 327 &pInterface, pTD, cpp_acquire ); 328 pInterface->release(); 329 TYPELIB_DANGER_RELEASE( pTD ); 330 *(void **)pRegisterReturn = pCallStack[1]; 331 eRet = typelib_TypeClass_ANY; 332 break; 333 } 334 TYPELIB_DANGER_RELEASE( pTD ); 335 } 336 } // else perform queryInterface() 337 default: 338 eRet = cpp2uno_call( 339 pCppI, aMemberDescr.get(), 340 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef, 341 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams, 342 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams, 343 pCallStack, pRegisterReturn ); 344 } 345 break; 346 } 347 default: 348 { 349 throw RuntimeException( 350 OUString::createFromAscii("no member description found!"), 351 (XInterface *)pCppI ); 352 // is here for dummy 353 eRet = typelib_TypeClass_VOID; 354 } 355 } 356 357 return eRet; 358 } 359 360 //================================================================================================== 361 /** 362 * is called on incoming vtable calls 363 * (called by asm snippets) 364 */ 365 static void cpp_vtable_call( int nTableEntry, void** pCallStack ) __attribute__((regparm(2))); 366 367 void cpp_vtable_call( int nTableEntry, void** pCallStack ) 368 { 369 volatile long nRegReturn[2]; 370 typelib_TypeClass aType = cpp_mediate( nTableEntry, pCallStack, (sal_Int64*)nRegReturn ); 371 372 switch( aType ) 373 { 374 case typelib_TypeClass_HYPER: 375 case typelib_TypeClass_UNSIGNED_HYPER: 376 __asm__( "movl %1, %%edx\n\t" 377 "movl %0, %%eax\n" 378 : : "m"(nRegReturn[0]), "m"(nRegReturn[1]) ); 379 break; 380 case typelib_TypeClass_FLOAT: 381 __asm__( "flds %0\n\t" 382 "fstp %%st(0)\n\t" 383 "flds %0\n" 384 : : "m"(*(float *)nRegReturn) ); 385 break; 386 case typelib_TypeClass_DOUBLE: 387 __asm__( "fldl %0\n\t" 388 "fstp %%st(0)\n\t" 389 "fldl %0\n" 390 : : "m"(*(double *)nRegReturn) ); 391 break; 392 // case typelib_TypeClass_UNSIGNED_SHORT: 393 // case typelib_TypeClass_SHORT: 394 // __asm__( "movswl %0, %%eax\n" 395 // : : "m"(nRegReturn) ); 396 // break; 397 default: 398 __asm__( "movl %0, %%eax\n" 399 : : "m"(nRegReturn[0]) ); 400 break; 401 } 402 } 403 404 405 //================================================================================================== 406 class MediateClassData 407 { 408 typedef ::std::hash_map< OUString, void *, OUStringHash > t_classdata_map; 409 t_classdata_map m_map; 410 Mutex m_mutex; 411 412 public: 413 void const * get_vtable( typelib_InterfaceTypeDescription * pTD ) SAL_THROW( () ); 414 415 inline MediateClassData() SAL_THROW( () ) 416 {} 417 ~MediateClassData() SAL_THROW( () ); 418 }; 419 //__________________________________________________________________________________________________ 420 MediateClassData::~MediateClassData() SAL_THROW( () ) 421 { 422 OSL_TRACE( "> calling ~MediateClassData(): freeing mediate vtables." ); 423 424 for ( t_classdata_map::const_iterator iPos( m_map.begin() ); iPos != m_map.end(); ++iPos ) 425 { 426 ::rtl_freeMemory( iPos->second ); 427 } 428 } 429 //-------------------------------------------------------------------------------------------------- 430 static inline void codeSnippet( char * code, sal_uInt32 vtable_pos, bool simple_ret_type ) SAL_THROW( () ) 431 { 432 if (! simple_ret_type) 433 vtable_pos |= 0x80000000; 434 OSL_ASSERT( sizeof (long) == 4 ); 435 // mov $nPos, %eax 436 *code++ = 0xb8; 437 *(long *)code = vtable_pos; 438 code += sizeof (long); 439 // mov %esp, %edx 440 *code++ = 0x89; 441 *code++ = 0xe2; 442 // jmp cpp_vtable_call 443 *code++ = 0xe9; 444 *(long *)code = ((char *)cpp_vtable_call) - code - sizeof (long); 445 } 446 //__________________________________________________________________________________________________ 447 void const * MediateClassData::get_vtable( typelib_InterfaceTypeDescription * pTD ) SAL_THROW( () ) 448 { 449 void * buffer; 450 451 // avoiding locked counts 452 OUString const & unoName = *(OUString const *)&((typelib_TypeDescription *)pTD)->pTypeName; 453 { 454 MutexGuard aGuard( m_mutex ); 455 t_classdata_map::const_iterator iFind( m_map.find( unoName ) ); 456 if (iFind == m_map.end()) 457 { 458 // create new vtable 459 sal_Int32 nSlots = pTD->nMapFunctionIndexToMemberIndex; 460 buffer = ::rtl_allocateMemory( ((2+ nSlots) * sizeof (void *)) + (nSlots *20) ); 461 462 ::std::pair< t_classdata_map::iterator, bool > insertion( 463 m_map.insert( t_classdata_map::value_type( unoName, buffer ) ) ); 464 OSL_ENSURE( insertion.second, "### inserting new vtable buffer failed?!" ); 465 466 void ** slots = (void **)buffer; 467 *slots++ = 0; 468 *slots++ = 0; // rtti 469 char * code = (char *)(slots + nSlots); 470 471 sal_uInt32 vtable_pos = 0; 472 sal_Int32 nAllMembers = pTD->nAllMembers; 473 typelib_TypeDescriptionReference ** ppAllMembers = pTD->ppAllMembers; 474 for ( sal_Int32 nPos = 0; nPos < nAllMembers; ++nPos ) 475 { 476 typelib_TypeDescription * pTD = 0; 477 TYPELIB_DANGER_GET( &pTD, ppAllMembers[ nPos ] ); 478 OSL_ASSERT( pTD ); 479 if (typelib_TypeClass_INTERFACE_ATTRIBUTE == pTD->eTypeClass) 480 { 481 bool simple_ret = cppu_isSimpleType( 482 ((typelib_InterfaceAttributeTypeDescription *)pTD)->pAttributeTypeRef->eTypeClass ); 483 // get method 484 *slots++ = code; 485 codeSnippet( code, vtable_pos++, simple_ret ); 486 code += 20; 487 if (! ((typelib_InterfaceAttributeTypeDescription *)pTD)->bReadOnly) 488 { 489 // set method 490 *slots++ = code; 491 codeSnippet( code, vtable_pos++, true ); 492 code += 20; 493 } 494 } 495 else 496 { 497 bool simple_ret = cppu_isSimpleType( 498 ((typelib_InterfaceMethodTypeDescription *)pTD)->pReturnTypeRef->eTypeClass ); 499 *slots++ = code; 500 codeSnippet( code, vtable_pos++, simple_ret ); 501 code += 20; 502 } 503 TYPELIB_DANGER_RELEASE( pTD ); 504 } 505 OSL_ASSERT( vtable_pos == nSlots ); 506 } 507 else 508 { 509 buffer = iFind->second; 510 } 511 } 512 513 return ((void **)buffer +2); 514 } 515 516 //================================================================================================== 517 void SAL_CALL cppu_cppInterfaceProxy_patchVtable( 518 XInterface * pCppI, typelib_InterfaceTypeDescription * pTypeDescr ) throw () 519 { 520 static MediateClassData * s_pMediateClassData = 0; 521 if (! s_pMediateClassData) 522 { 523 MutexGuard aGuard( Mutex::getGlobalMutex() ); 524 if (! s_pMediateClassData) 525 { 526 #ifdef LEAK_STATIC_DATA 527 s_pMediateClassData = new MediateClassData(); 528 #else 529 static MediateClassData s_aMediateClassData; 530 s_pMediateClassData = &s_aMediateClassData; 531 #endif 532 } 533 } 534 *(void const **)pCppI = s_pMediateClassData->get_vtable( pTypeDescr ); 535 } 536 537 } 538 539 extern "C" 540 { 541 //################################################################################################## 542 sal_Bool SAL_CALL component_canUnload( TimeValue * pTime ) 543 SAL_THROW_EXTERN_C() 544 { 545 return CPPU_CURRENT_NAMESPACE::g_moduleCount.canUnload( 546 &CPPU_CURRENT_NAMESPACE::g_moduleCount, pTime ); 547 } 548 //################################################################################################## 549 void SAL_CALL uno_initEnvironment( uno_Environment * pCppEnv ) 550 SAL_THROW_EXTERN_C() 551 { 552 CPPU_CURRENT_NAMESPACE::cppu_cppenv_initEnvironment( 553 pCppEnv ); 554 } 555 //################################################################################################## 556 void SAL_CALL uno_ext_getMapping( 557 uno_Mapping ** ppMapping, uno_Environment * pFrom, uno_Environment * pTo ) 558 SAL_THROW_EXTERN_C() 559 { 560 CPPU_CURRENT_NAMESPACE::cppu_ext_getMapping( 561 ppMapping, pFrom, pTo ); 562 } 563 } 564