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 int nr_gpr = 0; //number of gpr registers used 78 int nr_fpr = 0; //number of fpr regsiters 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 bool bFitsRegisters = x86_64::examine_argument( rParam.pTypeRef, false, nUsedGPR, nUsedSSE ); 127 if ( !rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ) ) // value 128 { 129 // Simple types must fit exactly one register on x86_64 130 OSL_ASSERT( bFitsRegisters && ( ( nUsedSSE == 1 && nUsedGPR == 0 ) || ( nUsedSSE == 0 && nUsedGPR == 1 ) ) ); 131 132 if ( nUsedSSE == 1 ) 133 { 134 if ( nr_fpr < x86_64::MAX_SSE_REGS ) 135 { 136 pCppArgs[nPos] = pUnoArgs[nPos] = fpreg++; 137 nr_fpr++; 138 } 139 else 140 pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw++; 141 } 142 else if ( nUsedGPR == 1 ) 143 { 144 if ( nr_gpr < x86_64::MAX_GPR_REGS ) 145 { 146 pCppArgs[nPos] = pUnoArgs[nPos] = gpreg++; 147 nr_gpr++; 148 } 149 else 150 pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw++; 151 } 152 153 // no longer needed 154 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 155 } 156 else // struct <= 16 bytes || ptr to complex value || ref 157 { 158 void *pCppStack; 159 char pTmpStruct[16]; 160 161 if ( bFitsRegisters && !rParam.bOut && 162 ( pParamTypeDescr->eTypeClass == typelib_TypeClass_STRUCT || 163 pParamTypeDescr->eTypeClass == typelib_TypeClass_EXCEPTION ) ) 164 { 165 if ( ( nr_gpr + nUsedGPR <= x86_64::MAX_GPR_REGS ) && ( nr_fpr + nUsedSSE <= x86_64::MAX_SSE_REGS ) ) 166 { 167 x86_64::fill_struct( rParam.pTypeRef, gpreg, fpreg, pTmpStruct ); 168 #if OSL_DEBUG_LEVEL > 1 169 fprintf( stderr, "nUsedGPR == %d, nUsedSSE == %d, pTmpStruct[0] == 0x%x, pTmpStruct[1] == 0x%x, **gpreg == 0x%lx\n", 170 nUsedGPR, nUsedSSE, pTmpStruct[0], pTmpStruct[1], *(sal_uInt64*)*gpreg ); 171 #endif 172 173 pCppArgs[nPos] = pCppStack = reinterpret_cast<void *>( pTmpStruct ); 174 gpreg += nUsedGPR; 175 fpreg += nUsedSSE; 176 } 177 else 178 pCppArgs[nPos] = pCppStack = *ovrflw++; 179 } 180 else if ( nr_gpr < x86_64::MAX_GPR_REGS ) 181 { 182 pCppArgs[nPos] = pCppStack = *gpreg++; 183 nr_gpr++; 184 } 185 else 186 pCppArgs[nPos] = pCppStack = *ovrflw++; 187 188 if (! rParam.bIn) // is pure out 189 { 190 // uno out is unconstructed mem! 191 pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ); 192 pTempIndizes[nTempIndizes] = nPos; 193 // will be released at reconversion 194 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 195 } 196 else if ( bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ) ) // is in/inout 197 { 198 uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ), 199 pCppStack, pParamTypeDescr, 200 pThis->getBridge()->getCpp2Uno() ); 201 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted 202 // will be released at reconversion 203 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 204 } 205 else // direct way 206 { 207 pUnoArgs[nPos] = pCppStack; 208 // no longer needed 209 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 210 } 211 } 212 } 213 214 // ExceptionHolder 215 uno_Any aUnoExc; // Any will be constructed by callee 216 uno_Any * pUnoExc = &aUnoExc; 217 218 // invoke uno dispatch call 219 (*pThis->getUnoI()->pDispatcher)( pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc ); 220 221 // in case an exception occured... 222 if ( pUnoExc ) 223 { 224 // destruct temporary in/inout params 225 for ( ; nTempIndizes--; ) 226 { 227 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 228 229 if (pParams[nIndex].bIn) // is in/inout => was constructed 230 uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], 0 ); 231 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] ); 232 } 233 if (pReturnTypeDescr) 234 TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); 235 236 CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc, pThis->getBridge()->getUno2Cpp() ); // has to destruct the any 237 // is here for dummy 238 return typelib_TypeClass_VOID; 239 } 240 else // else no exception occured... 241 { 242 // temporary params 243 for ( ; nTempIndizes--; ) 244 { 245 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 246 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes]; 247 248 if ( pParams[nIndex].bOut ) // inout/out 249 { 250 // convert and assign 251 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release ); 252 uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr, 253 pThis->getBridge()->getUno2Cpp() ); 254 } 255 // destroy temp uno param 256 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); 257 258 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 259 } 260 // return 261 if ( pCppReturn ) // has complex return 262 { 263 if ( pUnoReturn != pCppReturn ) // needs reconversion 264 { 265 uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr, 266 pThis->getBridge()->getUno2Cpp() ); 267 // destroy temp uno return 268 uno_destructData( pUnoReturn, pReturnTypeDescr, 0 ); 269 } 270 // complex return ptr is set to return reg 271 *(void **)pRegisterReturn = pCppReturn; 272 } 273 if ( pReturnTypeDescr ) 274 { 275 typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass; 276 TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); 277 return eRet; 278 } 279 else 280 return typelib_TypeClass_VOID; 281 } 282 } 283 284 285 //================================================================================================== 286 extern "C" typelib_TypeClass cpp_vtable_call( 287 sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset, 288 void ** gpreg, void ** fpreg, void ** ovrflw, 289 sal_uInt64 * pRegisterReturn /* space for register return */ ) 290 { 291 // gpreg: [ret *], this, [other gpr params] 292 // fpreg: [fpr params] 293 // ovrflw: [gpr or fpr params (properly aligned)] 294 void * pThis; 295 if ( nFunctionIndex & 0x80000000 ) 296 { 297 nFunctionIndex &= 0x7fffffff; 298 pThis = gpreg[1]; 299 } 300 else 301 { 302 pThis = gpreg[0]; 303 } 304 pThis = static_cast<char *>( pThis ) - nVtableOffset; 305 306 bridges::cpp_uno::shared::CppInterfaceProxy * pCppI = 307 bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( pThis ); 308 309 typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr(); 310 311 OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!\n" ); 312 if ( nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex ) 313 { 314 throw RuntimeException( OUString::createFromAscii("illegal vtable index!"), 315 reinterpret_cast<XInterface *>( pCppI ) ); 316 } 317 318 // determine called method 319 sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex]; 320 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!\n" ); 321 322 TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] ); 323 324 typelib_TypeClass eRet; 325 switch ( aMemberDescr.get()->eTypeClass ) 326 { 327 case typelib_TypeClass_INTERFACE_ATTRIBUTE: 328 { 329 typelib_TypeDescriptionReference *pAttrTypeRef = 330 reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( aMemberDescr.get() )->pAttributeTypeRef; 331 332 if ( pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex ) 333 { 334 // is GET method 335 eRet = cpp2uno_call( pCppI, aMemberDescr.get(), pAttrTypeRef, 336 0, 0, // no params 337 gpreg, fpreg, ovrflw, pRegisterReturn ); 338 } 339 else 340 { 341 // is SET method 342 typelib_MethodParameter aParam; 343 aParam.pTypeRef = pAttrTypeRef; 344 aParam.bIn = sal_True; 345 aParam.bOut = sal_False; 346 347 eRet = cpp2uno_call( pCppI, aMemberDescr.get(), 348 0, // indicates void return 349 1, &aParam, 350 gpreg, fpreg, ovrflw, pRegisterReturn ); 351 } 352 break; 353 } 354 case typelib_TypeClass_INTERFACE_METHOD: 355 { 356 // is METHOD 357 switch ( nFunctionIndex ) 358 { 359 case 1: // acquire() 360 pCppI->acquireProxy(); // non virtual call! 361 eRet = typelib_TypeClass_VOID; 362 break; 363 case 2: // release() 364 pCppI->releaseProxy(); // non virtual call! 365 eRet = typelib_TypeClass_VOID; 366 break; 367 case 0: // queryInterface() opt 368 { 369 typelib_TypeDescription * pTD = 0; 370 TYPELIB_DANGER_GET( &pTD, reinterpret_cast<Type *>( gpreg[2] )->getTypeLibType() ); 371 if ( pTD ) 372 { 373 XInterface * pInterface = 0; 374 (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface) 375 ( pCppI->getBridge()->getCppEnv(), 376 (void **)&pInterface, 377 pCppI->getOid().pData, 378 reinterpret_cast<typelib_InterfaceTypeDescription *>( pTD ) ); 379 380 if ( pInterface ) 381 { 382 ::uno_any_construct( reinterpret_cast<uno_Any *>( gpreg[0] ), 383 &pInterface, pTD, cpp_acquire ); 384 385 pInterface->release(); 386 TYPELIB_DANGER_RELEASE( pTD ); 387 388 reinterpret_cast<void **>( pRegisterReturn )[0] = gpreg[0]; 389 eRet = typelib_TypeClass_ANY; 390 break; 391 } 392 TYPELIB_DANGER_RELEASE( pTD ); 393 } 394 } // else perform queryInterface() 395 default: 396 { 397 typelib_InterfaceMethodTypeDescription *pMethodTD = 398 reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( aMemberDescr.get() ); 399 400 eRet = cpp2uno_call( pCppI, aMemberDescr.get(), 401 pMethodTD->pReturnTypeRef, 402 pMethodTD->nParams, 403 pMethodTD->pParams, 404 gpreg, fpreg, ovrflw, pRegisterReturn ); 405 } 406 } 407 break; 408 } 409 default: 410 { 411 throw RuntimeException( OUString::createFromAscii("no member description found!"), 412 reinterpret_cast<XInterface *>( pCppI ) ); 413 // is here for dummy 414 eRet = typelib_TypeClass_VOID; 415 } 416 } 417 418 return eRet; 419 } 420 421 //================================================================================================== 422 extern "C" void privateSnippetExecutor( ... ); 423 424 const int codeSnippetSize = 24; 425 426 // Generate a trampoline that redirects method calls to 427 // privateSnippetExecutor(). 428 // 429 // privateSnippetExecutor() saves all the registers that are used for 430 // parameter passing on x86_64, and calls the cpp_vtable_call(). 431 // When it returns, privateSnippetExecutor() sets the return value. 432 // 433 // Note: The code snippet we build here must not create a stack frame, 434 // otherwise the UNO exceptions stop working thanks to non-existing 435 // unwinding info. 436 unsigned char * codeSnippet( unsigned char * code, 437 sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset, 438 bool bHasHiddenParam ) SAL_THROW( () ) 439 { 440 sal_uInt64 nOffsetAndIndex = ( ( (sal_uInt64) nVtableOffset ) << 32 ) | ( (sal_uInt64) nFunctionIndex ); 441 442 if ( bHasHiddenParam ) 443 nOffsetAndIndex |= 0x80000000; 444 445 // movq $<nOffsetAndIndex>, %r10 446 *reinterpret_cast<sal_uInt16 *>( code ) = 0xba49; 447 *reinterpret_cast<sal_uInt64 *>( code + 2 ) = nOffsetAndIndex; 448 449 // movq $<address of the privateSnippetExecutor>, %r11 450 *reinterpret_cast<sal_uInt16 *>( code + 10 ) = 0xbb49; 451 *reinterpret_cast<sal_uInt64 *>( code + 12 ) = reinterpret_cast<sal_uInt64>( privateSnippetExecutor ); 452 453 // jmpq *%r11 454 *reinterpret_cast<sal_uInt32 *>( code + 20 ) = 0x00e3ff49; 455 456 return code + codeSnippetSize; 457 } 458 459 //================================================================================================== 460 struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; 461 462 bridges::cpp_uno::shared::VtableFactory::Slot * 463 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) 464 { 465 return static_cast< Slot * >(block) + 2; 466 } 467 468 //================================================================================================== 469 sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize( 470 sal_Int32 slotCount) 471 { 472 return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize; 473 } 474 475 //================================================================================================== 476 bridges::cpp_uno::shared::VtableFactory::Slot * 477 bridges::cpp_uno::shared::VtableFactory::initializeBlock( 478 void * block, sal_Int32 slotCount) 479 { 480 Slot * slots = mapBlockToVtable(block); 481 slots[-2].fn = 0; 482 slots[-1].fn = 0; 483 return slots + slotCount; 484 } 485 486 //================================================================================================== 487 488 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions( 489 Slot ** slots, unsigned char * code, 490 typelib_InterfaceTypeDescription const * type, sal_Int32 nFunctionOffset, 491 sal_Int32 functionCount, sal_Int32 nVtableOffset ) 492 { 493 (*slots) -= functionCount; 494 Slot * s = *slots; 495 496 for ( sal_Int32 nPos = 0; nPos < type->nMembers; ++nPos ) 497 { 498 typelib_TypeDescription * pTD = 0; 499 500 TYPELIB_DANGER_GET( &pTD, type->ppMembers[ nPos ] ); 501 OSL_ASSERT( pTD ); 502 503 if ( typelib_TypeClass_INTERFACE_ATTRIBUTE == pTD->eTypeClass ) 504 { 505 typelib_InterfaceAttributeTypeDescription *pAttrTD = 506 reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( pTD ); 507 508 // get method 509 (s++)->fn = code; 510 code = codeSnippet( code, nFunctionOffset++, nVtableOffset, 511 x86_64::return_in_hidden_param( pAttrTD->pAttributeTypeRef ) ); 512 513 if ( ! pAttrTD->bReadOnly ) 514 { 515 // set method 516 (s++)->fn = code; 517 code = codeSnippet( code, nFunctionOffset++, nVtableOffset, false ); 518 } 519 } 520 else if ( typelib_TypeClass_INTERFACE_METHOD == pTD->eTypeClass ) 521 { 522 typelib_InterfaceMethodTypeDescription *pMethodTD = 523 reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( pTD ); 524 525 (s++)->fn = code; 526 code = codeSnippet( code, nFunctionOffset++, nVtableOffset, 527 x86_64::return_in_hidden_param( pMethodTD->pReturnTypeRef ) ); 528 } 529 else 530 OSL_ASSERT( false ); 531 532 TYPELIB_DANGER_RELEASE( pTD ); 533 } 534 return code; 535 } 536 537 //================================================================================================== 538 void bridges::cpp_uno::shared::VtableFactory::flushCode( 539 unsigned char const *, unsigned char const * ) 540 { 541 } 542