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 #include <stdlib.h> 32 33 #include <com/sun/star/uno/genfunc.hxx> 34 #include "com/sun/star/uno/RuntimeException.hpp" 35 #include <uno/data.h> 36 37 #include "bridges/cpp_uno/shared/bridge.hxx" 38 #include "bridges/cpp_uno/shared/types.hxx" 39 #include "bridges/cpp_uno/shared/unointerfaceproxy.hxx" 40 #include "bridges/cpp_uno/shared/vtables.hxx" 41 42 #include "share.hxx" 43 44 using namespace ::rtl; 45 using namespace ::com::sun::star::uno; 46 #ifdef __GLIBCXX__ 47 using CPPU_CURRENT_NAMESPACE::__cxa_exception; 48 using CPPU_CURRENT_NAMESPACE::__cxa_get_globals; 49 #else 50 using __cxxabiv1::__cxa_exception; 51 using __cxxabiv1::__cxa_current_primary_exception; 52 using __cxxabiv1::__cxa_decrement_exception_refcount; 53 #endif 54 55 namespace 56 { 57 58 //================================================================================================== 59 // The call instruction within the asm section of callVirtualMethod may throw 60 // exceptions. So that the compiler handles this correctly, it is important 61 // that (a) callVirtualMethod might call dummy_can_throw_anything (although this 62 // never happens at runtime), which in turn can throw exceptions, and (b) 63 // callVirtualMethod is not inlined at its call site (so that any exceptions are 64 // caught which are thrown from the instruction calling callVirtualMethod): 65 void callVirtualMethod( 66 void * pAdjustedThisPtr, 67 sal_Int32 nVtableIndex, 68 void * pRegisterReturn, 69 typelib_TypeClass eReturnType, 70 sal_Int32 * pStackLongs, 71 sal_Int32 nStackLongs ) __attribute__((noinline)); 72 73 void callVirtualMethod( 74 void * pAdjustedThisPtr, 75 sal_Int32 nVtableIndex, 76 void * pRegisterReturn, 77 typelib_TypeClass eReturnType, 78 sal_Int32 * pStackLongs, 79 sal_Int32 nStackLongs ) 80 { 81 // parameter list is mixed list of * and values 82 // reference parameters are pointers 83 84 OSL_ENSURE( pStackLongs && pAdjustedThisPtr, "### null ptr!" ); 85 OSL_ENSURE( (sizeof(void *) == 4) && (sizeof(sal_Int32) == 4), "### unexpected size of int!" ); 86 OSL_ENSURE( nStackLongs && pStackLongs, "### no stack in callVirtualMethod !" ); 87 88 // never called 89 if (! pAdjustedThisPtr) CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything("xxx"); // address something 90 91 volatile long edx = 0, eax = 0; // for register returns 92 void * stackptr; 93 asm volatile ( 94 "mov %%esp, %6\n\t" 95 // preserve potential 128bit stack alignment 96 "and $0xfffffff0, %%esp\n\t" 97 "mov %0, %%eax\n\t" 98 "lea -4(,%%eax,4), %%eax\n\t" 99 "and $0xf, %%eax\n\t" 100 "sub $0xc, %%eax\n\t" 101 "add %%eax, %%esp\n\t" 102 // copy values 103 "mov %0, %%eax\n\t" 104 "mov %%eax, %%edx\n\t" 105 "dec %%edx\n\t" 106 "shl $2, %%edx\n\t" 107 "add %1, %%edx\n" 108 "Lcopy:\n\t" 109 "pushl 0(%%edx)\n\t" 110 "sub $4, %%edx\n\t" 111 "dec %%eax\n\t" 112 "jne Lcopy\n\t" 113 // do the actual call 114 "mov %2, %%edx\n\t" 115 "mov 0(%%edx), %%edx\n\t" 116 "mov %3, %%eax\n\t" 117 "shl $2, %%eax\n\t" 118 "add %%eax, %%edx\n\t" 119 "mov 0(%%edx), %%edx\n\t" 120 "call *%%edx\n\t" 121 // save return registers 122 "mov %%eax, %4\n\t" 123 "mov %%edx, %5\n\t" 124 // cleanup stack 125 "mov %6, %%esp\n\t" 126 : 127 : "m"(nStackLongs), "m"(pStackLongs), "m"(pAdjustedThisPtr), 128 "m"(nVtableIndex), "m"(eax), "m"(edx), "m"(stackptr) 129 : "eax", "edx" ); 130 switch( eReturnType ) 131 { 132 case typelib_TypeClass_HYPER: 133 case typelib_TypeClass_UNSIGNED_HYPER: 134 ((long*)pRegisterReturn)[1] = edx; 135 case typelib_TypeClass_LONG: 136 case typelib_TypeClass_UNSIGNED_LONG: 137 case typelib_TypeClass_CHAR: 138 case typelib_TypeClass_ENUM: 139 ((long*)pRegisterReturn)[0] = eax; 140 break; 141 case typelib_TypeClass_SHORT: 142 case typelib_TypeClass_UNSIGNED_SHORT: 143 *(unsigned short*)pRegisterReturn = eax; 144 break; 145 case typelib_TypeClass_BOOLEAN: 146 case typelib_TypeClass_BYTE: 147 *(unsigned char*)pRegisterReturn = eax; 148 break; 149 case typelib_TypeClass_FLOAT: 150 asm ( "fstps %0" : : "m"(*(char *)pRegisterReturn) ); 151 break; 152 case typelib_TypeClass_DOUBLE: 153 asm ( "fstpl %0\n\t" : : "m"(*(char *)pRegisterReturn) ); 154 break; 155 default: 156 break; 157 } 158 } 159 160 //================================================================================================== 161 static void cpp_call( 162 bridges::cpp_uno::shared::UnoInterfaceProxy * pThis, 163 bridges::cpp_uno::shared::VtableSlot aVtableSlot, 164 typelib_TypeDescriptionReference * pReturnTypeRef, 165 sal_Int32 nParams, typelib_MethodParameter * pParams, 166 void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc ) 167 { 168 // max space for: [complex ret ptr], values|ptr ... 169 char * pCppStack = 170 (char *)alloca( sizeof(sal_Int32) + ((nParams+2) * sizeof(sal_Int64)) ); 171 char * pCppStackStart = pCppStack; 172 173 // return 174 typelib_TypeDescription * pReturnTypeDescr = 0; 175 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef ); 176 OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" ); 177 178 void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion 179 180 if (pReturnTypeDescr) 181 { 182 if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr )) 183 { 184 pCppReturn = pUnoReturn; // direct way for simple types 185 } 186 else 187 { 188 // complex return via ptr 189 pCppReturn = *(void **)pCppStack 190 = (bridges::cpp_uno::shared::relatesToInterfaceType( 191 pReturnTypeDescr ) 192 ? alloca( pReturnTypeDescr->nSize ) 193 : pUnoReturn); // direct way 194 pCppStack += sizeof(void *); 195 } 196 } 197 // push this 198 void * pAdjustedThisPtr = reinterpret_cast< void ** >(pThis->getCppI()) 199 + aVtableSlot.offset; 200 *(void**)pCppStack = pAdjustedThisPtr; 201 pCppStack += sizeof( void* ); 202 203 // stack space 204 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" ); 205 // args 206 void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams ); 207 // indizes of values this have to be converted (interface conversion cpp<=>uno) 208 sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams); 209 // type descriptions for reconversions 210 typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams)); 211 212 sal_Int32 nTempIndizes = 0; 213 214 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) 215 { 216 const typelib_MethodParameter & rParam = pParams[nPos]; 217 typelib_TypeDescription * pParamTypeDescr = 0; 218 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef ); 219 220 if (!rParam.bOut 221 && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr )) 222 { 223 uno_copyAndConvertData( pCppArgs[nPos] = pCppStack, pUnoArgs[nPos], pParamTypeDescr, 224 pThis->getBridge()->getUno2Cpp() ); 225 226 switch (pParamTypeDescr->eTypeClass) 227 { 228 case typelib_TypeClass_HYPER: 229 case typelib_TypeClass_UNSIGNED_HYPER: 230 case typelib_TypeClass_DOUBLE: 231 pCppStack += sizeof(sal_Int32); // extra long 232 break; 233 default: 234 break; 235 } 236 // no longer needed 237 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 238 } 239 else // ptr to complex value | ref 240 { 241 if (! rParam.bIn) // is pure out 242 { 243 // cpp out is constructed mem, uno out is not! 244 uno_constructData( 245 *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ), 246 pParamTypeDescr ); 247 pTempIndizes[nTempIndizes] = nPos; // default constructed for cpp call 248 // will be released at reconversion 249 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 250 } 251 // is in/inout 252 else if (bridges::cpp_uno::shared::relatesToInterfaceType( 253 pParamTypeDescr )) 254 { 255 uno_copyAndConvertData( 256 *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ), 257 pUnoArgs[nPos], pParamTypeDescr, 258 pThis->getBridge()->getUno2Cpp() ); 259 260 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted 261 // will be released at reconversion 262 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 263 } 264 else // direct way 265 { 266 *(void **)pCppStack = pCppArgs[nPos] = pUnoArgs[nPos]; 267 // no longer needed 268 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 269 } 270 } 271 pCppStack += sizeof(sal_Int32); // standard parameter length 272 } 273 274 try 275 { 276 OSL_ENSURE( !( (pCppStack - pCppStackStart ) & 3), "UNALIGNED STACK !!! (Please DO panic)" ); 277 callVirtualMethod( 278 pAdjustedThisPtr, aVtableSlot.index, 279 pCppReturn, pReturnTypeDescr->eTypeClass, 280 (sal_Int32 *)pCppStackStart, (pCppStack - pCppStackStart) / sizeof(sal_Int32) ); 281 // NO exception occurred... 282 *ppUnoExc = 0; 283 284 // reconvert temporary params 285 for ( ; nTempIndizes--; ) 286 { 287 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 288 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes]; 289 290 if (pParams[nIndex].bIn) 291 { 292 if (pParams[nIndex].bOut) // inout 293 { 294 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value 295 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr, 296 pThis->getBridge()->getCpp2Uno() ); 297 } 298 } 299 else // pure out 300 { 301 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr, 302 pThis->getBridge()->getCpp2Uno() ); 303 } 304 // destroy temp cpp param => cpp: every param was constructed 305 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release ); 306 307 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 308 } 309 // return value 310 if (pCppReturn && pUnoReturn != pCppReturn) 311 { 312 uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr, 313 pThis->getBridge()->getCpp2Uno() ); 314 uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release ); 315 } 316 } 317 catch (...) 318 { 319 __cxa_exception *header; 320 #ifdef __GLIBCXX__ 321 header = __cxa_get_globals()->caughtExceptions; 322 #else 323 header = reinterpret_cast<__cxa_exception *>( __cxa_current_primary_exception() ); 324 if (header) { 325 __cxa_decrement_exception_refcount( header ); 326 header--; 327 uint64_t exc_class = header->unwindHeader.exception_class 328 & 0xffffffffffffff00; 329 if (exc_class != /* "GNUCC++" */ 0x474e5543432b2b00) { 330 // _Unwind_Exception was made __aligned__ which 331 // increased its size by 12 bytes. 332 header = reinterpret_cast<__cxa_exception *>( 333 reinterpret_cast<char *>( header ) - 12 ); 334 exc_class = header->unwindHeader.exception_class 335 & 0xffffffffffffff00; 336 if (exc_class != /* "GNUCC++" */ 0x474e5543432b2b00) { 337 header = nullptr; 338 } 339 } 340 } 341 #endif 342 // fill uno exception 343 CPPU_CURRENT_NAMESPACE::fillUnoException( header, *ppUnoExc, pThis->getBridge()->getCpp2Uno() ); 344 345 // temporary params 346 for ( ; nTempIndizes--; ) 347 { 348 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 349 // destroy temp cpp param => cpp: every param was constructed 350 uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], cpp_release ); 351 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] ); 352 } 353 // return type 354 if (pReturnTypeDescr) 355 TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); 356 } 357 } 358 359 } 360 361 namespace bridges { namespace cpp_uno { namespace shared { 362 363 void unoInterfaceProxyDispatch( 364 uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr, 365 void * pReturn, void * pArgs[], uno_Any ** ppException ) 366 { 367 // is my surrogate 368 bridges::cpp_uno::shared::UnoInterfaceProxy * pThis 369 = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI); 370 371 switch (pMemberDescr->eTypeClass) 372 { 373 case typelib_TypeClass_INTERFACE_ATTRIBUTE: 374 { 375 VtableSlot aVtableSlot( 376 getVtableSlot( 377 reinterpret_cast< 378 typelib_InterfaceAttributeTypeDescription const * >( 379 pMemberDescr))); 380 if (pReturn) 381 { 382 // dependent dispatch 383 cpp_call( 384 pThis, aVtableSlot, 385 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef, 386 0, 0, // no params 387 pReturn, pArgs, ppException ); 388 } 389 else 390 { 391 // is SET 392 typelib_MethodParameter aParam; 393 aParam.pTypeRef = 394 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef; 395 aParam.bIn = sal_True; 396 aParam.bOut = sal_False; 397 398 typelib_TypeDescriptionReference * pReturnTypeRef = 0; 399 OUString aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") ); 400 typelib_typedescriptionreference_new( 401 &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData ); 402 403 // dependent dispatch 404 aVtableSlot.index += 1; // get, then set method 405 cpp_call( 406 pThis, aVtableSlot, 407 pReturnTypeRef, 408 1, &aParam, 409 pReturn, pArgs, ppException ); 410 411 typelib_typedescriptionreference_release( pReturnTypeRef ); 412 } 413 414 break; 415 } 416 case typelib_TypeClass_INTERFACE_METHOD: 417 { 418 VtableSlot aVtableSlot( 419 getVtableSlot( 420 reinterpret_cast< 421 typelib_InterfaceMethodTypeDescription const * >( 422 pMemberDescr))); 423 switch (aVtableSlot.index) 424 { 425 // standard calls 426 case 1: // acquire uno interface 427 (*pUnoI->acquire)( pUnoI ); 428 *ppException = 0; 429 break; 430 case 2: // release uno interface 431 (*pUnoI->release)( pUnoI ); 432 *ppException = 0; 433 break; 434 case 0: // queryInterface() opt 435 { 436 typelib_TypeDescription * pTD = 0; 437 TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() ); 438 if (pTD) 439 { 440 uno_Interface * pInterface = 0; 441 (*pThis->pBridge->getUnoEnv()->getRegisteredInterface)( 442 pThis->pBridge->getUnoEnv(), 443 (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD ); 444 445 if (pInterface) 446 { 447 ::uno_any_construct( 448 reinterpret_cast< uno_Any * >( pReturn ), 449 &pInterface, pTD, 0 ); 450 (*pInterface->release)( pInterface ); 451 TYPELIB_DANGER_RELEASE( pTD ); 452 *ppException = 0; 453 break; 454 } 455 TYPELIB_DANGER_RELEASE( pTD ); 456 } 457 } // else perform queryInterface() 458 default: 459 // dependent dispatch 460 cpp_call( 461 pThis, aVtableSlot, 462 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef, 463 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams, 464 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams, 465 pReturn, pArgs, ppException ); 466 } 467 break; 468 } 469 default: 470 { 471 ::com::sun::star::uno::RuntimeException aExc( 472 OUString( RTL_CONSTASCII_USTRINGPARAM("illegal member type description!") ), 473 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() ); 474 475 Type const & rExcType = ::getCppuType( &aExc ); 476 // binary identical null reference 477 ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 ); 478 } 479 } 480 } 481 482 } } } 483