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