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