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 33 // #include <malloc.h> 34 35 #include <com/sun/star/uno/genfunc.hxx> 36 #include "com/sun/star/uno/RuntimeException.hpp" 37 #include <uno/data.h> 38 39 #include "bridges/cpp_uno/shared/bridge.hxx" 40 #include "bridges/cpp_uno/shared/types.hxx" 41 #include "bridges/cpp_uno/shared/unointerfaceproxy.hxx" 42 #include "bridges/cpp_uno/shared/vtables.hxx" 43 44 #include "share.hxx" 45 46 using namespace ::rtl; 47 using namespace ::com::sun::star::uno; 48 49 namespace 50 { 51 52 //================================================================================================== 53 // The call instruction within the asm section of callVirtualMethod may throw 54 // exceptions. So that the compiler handles this correctly, it is important 55 // that (a) callVirtualMethod might call dummy_can_throw_anything (although this 56 // never happens at runtime), which in turn can throw exceptions, and (b) 57 // callVirtualMethod is not inlined at its call site (so that any exceptions are 58 // caught which are thrown from the instruction calling callVirtualMethod): 59 void callVirtualMethod( 60 void * pAdjustedThisPtr, 61 sal_Int32 nVtableIndex, 62 void * pRegisterReturn, 63 typelib_TypeDescription * pReturnTypeDescr, bool bSimpleReturn, 64 sal_Int32 * pStackLongs, 65 sal_Int32 nStackLongs ) __attribute__((noinline)); 66 67 void callVirtualMethod( 68 void * pAdjustedThisPtr, 69 sal_Int32 nVtableIndex, 70 void * pRegisterReturn, 71 typelib_TypeDescription * pReturnTypeDescr, bool bSimpleReturn, 72 sal_Int32 * pStackLongs, 73 sal_Int32 nStackLongs ) 74 { 75 // parameter list is mixed list of * and values 76 // reference parameters are pointers 77 78 OSL_ENSURE( pStackLongs && pAdjustedThisPtr, "### null ptr!" ); 79 OSL_ENSURE( (sizeof(void *) == 4) && (sizeof(sal_Int32) == 4), "### unexpected size of int!" ); 80 OSL_ENSURE( nStackLongs && pStackLongs, "### no stack in callVirtualMethod !" ); 81 82 // never called 83 if (! pAdjustedThisPtr) CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything("xxx"); // address something 84 85 volatile long edx = 0, eax = 0; // for register returns 86 void * stackptr; 87 asm volatile ( 88 "mov %%esp, %6\n\t" 89 "mov %0, %%eax\n\t" 90 "mov %%eax, %%edx\n\t" 91 // stack padding to keep stack aligned: 92 "shl $2, %%eax\n\t" 93 "neg %%eax\n\t" 94 "add %%esp, %%eax\n\t" 95 "and $0xf, %%eax\n\t" 96 "sub %%eax, %%esp\n\t" 97 // copy: 98 "mov %%edx, %%eax\n\t" 99 "dec %%edx\n\t" 100 "shl $2, %%edx\n\t" 101 "add %1, %%edx\n" 102 "Lcopy:\n\t" 103 "pushl 0(%%edx)\n\t" 104 "sub $4, %%edx\n\t" 105 "dec %%eax\n\t" 106 "jne Lcopy\n\t" 107 // do the actual call 108 "mov %2, %%edx\n\t" 109 "mov 0(%%edx), %%edx\n\t" 110 "mov %3, %%eax\n\t" 111 "shl $2, %%eax\n\t" 112 "add %%eax, %%edx\n\t" 113 "mov 0(%%edx), %%edx\n\t" 114 "call *%%edx\n\t" 115 // save return registers 116 "mov %%eax, %4\n\t" 117 "mov %%edx, %5\n\t" 118 // cleanup stack 119 "mov %6, %%esp\n\t" 120 : 121 : "m"(nStackLongs), "m"(pStackLongs), "m"(pAdjustedThisPtr), 122 "m"(nVtableIndex), "m"(eax), "m"(edx), "m"(stackptr) 123 : "eax", "edx" ); 124 switch( pReturnTypeDescr->eTypeClass ) 125 { 126 case typelib_TypeClass_VOID: 127 break; 128 case typelib_TypeClass_HYPER: 129 case typelib_TypeClass_UNSIGNED_HYPER: 130 ((long*)pRegisterReturn)[1] = edx; 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