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