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