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