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