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 <stdio.h> 32 #include <stdlib.h> 33 #include <hash_map> 34 35 #include <rtl/alloc.h> 36 #include <osl/mutex.hxx> 37 38 #include <com/sun/star/uno/genfunc.hxx> 39 #include "com/sun/star/uno/RuntimeException.hpp" 40 #include <uno/data.h> 41 #include <typelib/typedescription.hxx> 42 43 #include "bridges/cpp_uno/shared/bridge.hxx" 44 #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx" 45 #include "bridges/cpp_uno/shared/types.hxx" 46 #include "bridges/cpp_uno/shared/vtablefactory.hxx" 47 48 #include "abi.hxx" 49 #include "share.hxx" 50 51 using namespace ::osl; 52 using namespace ::rtl; 53 using namespace ::com::sun::star::uno; 54 55 //================================================================================================== 56 57 // Perform the UNO call 58 // 59 // We must convert the paramaters stored in gpreg, fpreg and ovrflw to UNO 60 // arguments and call pThis->getUnoI()->pDispatcher. 61 // 62 // gpreg: [ret *], this, [gpr params] 63 // fpreg: [fpr params] 64 // ovrflw: [gpr or fpr params (properly aligned)] 65 // 66 // [ret *] is present when we are returning a structure bigger than 16 bytes 67 // Simple types are returned in rax, rdx (int), or xmm0, xmm1 (fp). 68 // Similarly structures <= 16 bytes are in rax, rdx, xmm0, xmm1 as necessary. 69 static typelib_TypeClass cpp2uno_call( 70 bridges::cpp_uno::shared::CppInterfaceProxy * pThis, 71 const typelib_TypeDescription * pMemberTypeDescr, 72 typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return 73 sal_Int32 nParams, typelib_MethodParameter * pParams, 74 void ** gpreg, void ** fpreg, void ** ovrflw, 75 sal_uInt64 * pRegisterReturn /* space for register return */ ) 76 { 77 unsigned int nr_gpr = 0; //number of gpr registers used 78 unsigned int nr_fpr = 0; //number of fpr registers used 79 80 // return 81 typelib_TypeDescription * pReturnTypeDescr = 0; 82 if (pReturnTypeRef) 83 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef ); 84 85 void * pUnoReturn = 0; 86 void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need 87 88 if ( pReturnTypeDescr ) 89 { 90 if ( x86_64::return_in_hidden_param( pReturnTypeRef ) ) 91 { 92 pCppReturn = *gpreg++; 93 nr_gpr++; 94 95 pUnoReturn = ( bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr ) 96 ? alloca( pReturnTypeDescr->nSize ) 97 : pCppReturn ); // direct way 98 } 99 else 100 pUnoReturn = pRegisterReturn; // direct way for simple types 101 } 102 103 // pop this 104 gpreg++; 105 nr_gpr++; 106 107 // stack space 108 // parameters 109 void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams ); 110 void ** pCppArgs = pUnoArgs + nParams; 111 // indizes of values this have to be converted (interface conversion cpp<=>uno) 112 sal_Int32 * pTempIndizes = (sal_Int32 *)(pUnoArgs + (2 * nParams)); 113 // type descriptions for reconversions 114 typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams)); 115 116 sal_Int32 nTempIndizes = 0; 117 118 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) 119 { 120 const typelib_MethodParameter & rParam = pParams[nPos]; 121 typelib_TypeDescription * pParamTypeDescr = 0; 122 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef ); 123 124 int nUsedGPR = 0; 125 int nUsedSSE = 0; 126 #if OSL_DEBUG_LEVEL > 1 127 bool bFitsRegisters = 128 #endif 129 x86_64::examine_argument( rParam.pTypeRef, false, nUsedGPR, nUsedSSE ); 130 if ( !rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ) ) // value 131 { 132 // Simple types must fit exactly one register on x86_64 133 OSL_ASSERT( bFitsRegisters && ( ( nUsedSSE == 1 && nUsedGPR == 0 ) || ( nUsedSSE == 0 && nUsedGPR == 1 ) ) ); 134 135 if ( nUsedSSE == 1 ) 136 { 137 if ( nr_fpr < x86_64::MAX_SSE_REGS ) 138 { 139 pCppArgs[nPos] = pUnoArgs[nPos] = fpreg++; 140 nr_fpr++; 141 } 142 else 143 pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw++; 144 } 145 else if ( nUsedGPR == 1 ) 146 { 147 if ( nr_gpr < x86_64::MAX_GPR_REGS ) 148 { 149 pCppArgs[nPos] = pUnoArgs[nPos] = gpreg++; 150 nr_gpr++; 151 } 152 else 153 pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw++; 154 } 155 156 // no longer needed 157 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 158 } 159 else // struct <= 16 bytes || ptr to complex value || ref 160 { 161 void *pCppStack; 162 if ( nr_gpr < x86_64::MAX_GPR_REGS ) 163 { 164 pCppArgs[nPos] = pCppStack = *gpreg++; 165 nr_gpr++; 166 } 167 else 168 pCppArgs[nPos] = pCppStack = *ovrflw++; 169 170 if (! rParam.bIn) // is pure out 171 { 172 // uno out is unconstructed mem! 173 pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ); 174 pTempIndizes[nTempIndizes] = nPos; 175 // will be released at reconversion 176 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 177 } 178 else if ( bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ) ) // is in/inout 179 { 180 uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ), 181 pCppStack, pParamTypeDescr, 182 pThis->getBridge()->getCpp2Uno() ); 183 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted 184 // will be released at reconversion 185 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 186 } 187 else // direct way 188 { 189 pUnoArgs[nPos] = pCppStack; 190 // no longer needed 191 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 192 } 193 } 194 } 195 196 // ExceptionHolder 197 uno_Any aUnoExc; // Any will be constructed by callee 198 uno_Any * pUnoExc = &aUnoExc; 199 200 // invoke uno dispatch call 201 (*pThis->getUnoI()->pDispatcher)( pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc ); 202 203 // in case an exception occured... 204 if ( pUnoExc ) 205 { 206 // destruct temporary in/inout params 207 for ( ; nTempIndizes--; ) 208 { 209 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 210 211 if (pParams[nIndex].bIn) // is in/inout => was constructed 212 uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], 0 ); 213 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] ); 214 } 215 if (pReturnTypeDescr) 216 TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); 217 218 CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc, pThis->getBridge()->getUno2Cpp() ); // has to destruct the any 219 // is here for dummy 220 return typelib_TypeClass_VOID; 221 } 222 else // else no exception occured... 223 { 224 // temporary params 225 for ( ; nTempIndizes--; ) 226 { 227 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 228 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes]; 229 230 if ( pParams[nIndex].bOut ) // inout/out 231 { 232 // convert and assign 233 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release ); 234 uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr, 235 pThis->getBridge()->getUno2Cpp() ); 236 } 237 // destroy temp uno param 238 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); 239 240 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 241 } 242 // return 243 if ( pCppReturn ) // has complex return 244 { 245 if ( pUnoReturn != pCppReturn ) // needs reconversion 246 { 247 uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr, 248 pThis->getBridge()->getUno2Cpp() ); 249 // destroy temp uno return 250 uno_destructData( pUnoReturn, pReturnTypeDescr, 0 ); 251 } 252 // complex return ptr is set to return reg 253 *(void **)pRegisterReturn = pCppReturn; 254 } 255 if ( pReturnTypeDescr ) 256 { 257 typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass; 258 TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); 259 return eRet; 260 } 261 else 262 return typelib_TypeClass_VOID; 263 } 264 } 265 266 267 //================================================================================================== 268 extern "C" typelib_TypeClass cpp_vtable_call( 269 sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset, 270 void ** gpreg, void ** fpreg, void ** ovrflw, 271 sal_uInt64 * pRegisterReturn /* space for register return */ ) 272 { 273 // gpreg: [ret *], this, [other gpr params] 274 // fpreg: [fpr params] 275 // ovrflw: [gpr or fpr params (properly aligned)] 276 void * pThis; 277 if ( nFunctionIndex & 0x80000000 ) 278 { 279 nFunctionIndex &= 0x7fffffff; 280 pThis = gpreg[1]; 281 } 282 else 283 { 284 pThis = gpreg[0]; 285 } 286 pThis = static_cast<char *>( pThis ) - nVtableOffset; 287 288 bridges::cpp_uno::shared::CppInterfaceProxy * pCppI = 289 bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( pThis ); 290 291 typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr(); 292 293 OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!\n" ); 294 if ( nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex ) 295 { 296 throw RuntimeException( OUString::createFromAscii("illegal vtable index!"), 297 reinterpret_cast<XInterface *>( pCppI ) ); 298 } 299 300 // determine called method 301 sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex]; 302 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!\n" ); 303 304 TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] ); 305 306 typelib_TypeClass eRet; 307 switch ( aMemberDescr.get()->eTypeClass ) 308 { 309 case typelib_TypeClass_INTERFACE_ATTRIBUTE: 310 { 311 typelib_TypeDescriptionReference *pAttrTypeRef = 312 reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( aMemberDescr.get() )->pAttributeTypeRef; 313 314 if ( pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex ) 315 { 316 // is GET method 317 eRet = cpp2uno_call( pCppI, aMemberDescr.get(), pAttrTypeRef, 318 0, 0, // no params 319 gpreg, fpreg, ovrflw, pRegisterReturn ); 320 } 321 else 322 { 323 // is SET method 324 typelib_MethodParameter aParam; 325 aParam.pTypeRef = pAttrTypeRef; 326 aParam.bIn = sal_True; 327 aParam.bOut = sal_False; 328 329 eRet = cpp2uno_call( pCppI, aMemberDescr.get(), 330 0, // indicates void return 331 1, &aParam, 332 gpreg, fpreg, ovrflw, pRegisterReturn ); 333 } 334 break; 335 } 336 case typelib_TypeClass_INTERFACE_METHOD: 337 { 338 // is METHOD 339 switch ( nFunctionIndex ) 340 { 341 case 1: // acquire() 342 pCppI->acquireProxy(); // non virtual call! 343 eRet = typelib_TypeClass_VOID; 344 break; 345 case 2: // release() 346 pCppI->releaseProxy(); // non virtual call! 347 eRet = typelib_TypeClass_VOID; 348 break; 349 case 0: // queryInterface() opt 350 { 351 typelib_TypeDescription * pTD = 0; 352 TYPELIB_DANGER_GET( &pTD, reinterpret_cast<Type *>( gpreg[2] )->getTypeLibType() ); 353 if ( pTD ) 354 { 355 XInterface * pInterface = 0; 356 (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface) 357 ( pCppI->getBridge()->getCppEnv(), 358 (void **)&pInterface, 359 pCppI->getOid().pData, 360 reinterpret_cast<typelib_InterfaceTypeDescription *>( pTD ) ); 361 362 if ( pInterface ) 363 { 364 ::uno_any_construct( reinterpret_cast<uno_Any *>( gpreg[0] ), 365 &pInterface, pTD, cpp_acquire ); 366 367 pInterface->release(); 368 TYPELIB_DANGER_RELEASE( pTD ); 369 370 reinterpret_cast<void **>( pRegisterReturn )[0] = gpreg[0]; 371 eRet = typelib_TypeClass_ANY; 372 break; 373 } 374 TYPELIB_DANGER_RELEASE( pTD ); 375 } 376 } // else perform queryInterface() 377 default: 378 { 379 typelib_InterfaceMethodTypeDescription *pMethodTD = 380 reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( aMemberDescr.get() ); 381 382 eRet = cpp2uno_call( pCppI, aMemberDescr.get(), 383 pMethodTD->pReturnTypeRef, 384 pMethodTD->nParams, 385 pMethodTD->pParams, 386 gpreg, fpreg, ovrflw, pRegisterReturn ); 387 } 388 } 389 break; 390 } 391 default: 392 { 393 throw RuntimeException( OUString::createFromAscii("no member description found!"), 394 reinterpret_cast<XInterface *>( pCppI ) ); 395 // is here for dummy 396 eRet = typelib_TypeClass_VOID; 397 } 398 } 399 400 return eRet; 401 } 402 403 //================================================================================================== 404 extern "C" void privateSnippetExecutor( ... ); 405 406 const int codeSnippetSize = 24; 407 408 // Generate a trampoline that redirects method calls to 409 // privateSnippetExecutor(). 410 // 411 // privateSnippetExecutor() saves all the registers that are used for 412 // parameter passing on x86_64, and calls the cpp_vtable_call(). 413 // When it returns, privateSnippetExecutor() sets the return value. 414 // 415 // Note: The code snippet we build here must not create a stack frame, 416 // otherwise the UNO exceptions stop working thanks to non-existing 417 // unwinding info. 418 unsigned char * codeSnippet( unsigned char * code, 419 sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset, 420 bool bHasHiddenParam ) SAL_THROW( () ) 421 { 422 sal_uInt64 nOffsetAndIndex = ( ( (sal_uInt64) nVtableOffset ) << 32 ) | ( (sal_uInt64) nFunctionIndex ); 423 424 if ( bHasHiddenParam ) 425 nOffsetAndIndex |= 0x80000000; 426 427 // movq $<nOffsetAndIndex>, %r10 428 *reinterpret_cast<sal_uInt16 *>( code ) = 0xba49; 429 *reinterpret_cast<sal_uInt64 *>( code + 2 ) = nOffsetAndIndex; 430 431 // movq $<address of the privateSnippetExecutor>, %r11 432 *reinterpret_cast<sal_uInt16 *>( code + 10 ) = 0xbb49; 433 *reinterpret_cast<sal_uInt64 *>( code + 12 ) = reinterpret_cast<sal_uInt64>( privateSnippetExecutor ); 434 435 // jmpq *%r11 436 *reinterpret_cast<sal_uInt32 *>( code + 20 ) = 0x00e3ff49; 437 438 return code + codeSnippetSize; 439 } 440 441 //================================================================================================== 442 struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; 443 444 bridges::cpp_uno::shared::VtableFactory::Slot * 445 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) 446 { 447 return static_cast< Slot * >(block) + 2; 448 } 449 450 //================================================================================================== 451 sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize( 452 sal_Int32 slotCount) 453 { 454 return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize; 455 } 456 457 //================================================================================================== 458 bridges::cpp_uno::shared::VtableFactory::Slot * 459 bridges::cpp_uno::shared::VtableFactory::initializeBlock( 460 void * block, sal_Int32 slotCount) 461 { 462 Slot * slots = mapBlockToVtable(block); 463 slots[-2].fn = 0; 464 slots[-1].fn = 0; 465 return slots + slotCount; 466 } 467 468 //================================================================================================== 469 470 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions( 471 Slot ** slots, unsigned char * code, sal_PtrDiff writetoexecdiff, 472 typelib_InterfaceTypeDescription const * type, sal_Int32 nFunctionOffset, 473 sal_Int32 functionCount, sal_Int32 nVtableOffset ) 474 { 475 (*slots) -= functionCount; 476 Slot * s = *slots; 477 for ( sal_Int32 nPos = 0; nPos < type->nMembers; ++nPos ) 478 { 479 typelib_TypeDescription * pTD = 0; 480 481 TYPELIB_DANGER_GET( &pTD, type->ppMembers[ nPos ] ); 482 OSL_ASSERT( pTD ); 483 484 if ( typelib_TypeClass_INTERFACE_ATTRIBUTE == pTD->eTypeClass ) 485 { 486 typelib_InterfaceAttributeTypeDescription *pAttrTD = 487 reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( pTD ); 488 489 // get method 490 (s++)->fn = code + writetoexecdiff; 491 code = codeSnippet( code, nFunctionOffset++, nVtableOffset, 492 x86_64::return_in_hidden_param( pAttrTD->pAttributeTypeRef ) ); 493 494 if ( ! pAttrTD->bReadOnly ) 495 { 496 // set method 497 (s++)->fn = code + writetoexecdiff; 498 code = codeSnippet( code, nFunctionOffset++, nVtableOffset, false ); 499 } 500 } 501 else if ( typelib_TypeClass_INTERFACE_METHOD == pTD->eTypeClass ) 502 { 503 typelib_InterfaceMethodTypeDescription *pMethodTD = 504 reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( pTD ); 505 506 (s++)->fn = code + writetoexecdiff; 507 code = codeSnippet( code, nFunctionOffset++, nVtableOffset, 508 x86_64::return_in_hidden_param( pMethodTD->pReturnTypeRef ) ); 509 } 510 else 511 OSL_ASSERT( false ); 512 513 TYPELIB_DANGER_RELEASE( pTD ); 514 } 515 return code; 516 } 517 518 //================================================================================================== 519 void bridges::cpp_uno::shared::VtableFactory::flushCode( 520 unsigned char const *, unsigned char const * ) 521 { 522 } 523