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 #include <malloc.h> 29 #include <rtl/alloc.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 #include <stdio.h> 43 #include <string.h> 44 45 using namespace ::rtl; 46 using namespace ::com::sun::star::uno; 47 48 void callVirtualMethod(void * pThis, sal_uInt32 nVtableIndex, 49 void * pRegisterReturn, typelib_TypeDescription *pReturnTypeDescr, bool bRegisterReturn, 50 sal_uInt32 *pStack, sal_uInt32 nStack, sal_uInt32 *pGPR, double *pFPR); 51 52 #define INSERT_INT32( pSV, nr, pGPR, pDS, bOverFlow )\ 53 if (nr < hppa::MAX_WORDS_IN_REGS) \ 54 { \ 55 pGPR[nr++] = *reinterpret_cast<sal_uInt32 *>( pSV ); \ 56 } \ 57 else \ 58 bOverFlow = true; \ 59 if (bOverFlow) \ 60 *pDS++ = *reinterpret_cast<sal_uInt32 *>( pSV ); 61 62 #define INSERT_INT64( pSV, nr, pGPR, pDS, pStart, bOverFlow )\ 63 if ( (nr < hppa::MAX_WORDS_IN_REGS) && (nr % 2) ) \ 64 { \ 65 ++nr; \ 66 } \ 67 if ( nr < hppa::MAX_WORDS_IN_REGS ) \ 68 { \ 69 pGPR[nr++] = *reinterpret_cast<sal_uInt32 *>( pSV ); \ 70 pGPR[nr++] = *(reinterpret_cast<sal_uInt32 *>( pSV ) + 1); \ 71 } \ 72 else \ 73 bOverFlow = true; \ 74 if ( bOverFlow ) \ 75 { \ 76 if ( (pDS - pStart) % 2) \ 77 ++pDS; \ 78 *pDS++ = reinterpret_cast<sal_uInt32 *>( pSV )[1]; \ 79 *pDS++ = reinterpret_cast<sal_uInt32 *>( pSV )[0]; \ 80 } 81 82 #define INSERT_FLOAT( pSV, nr, pFPR, pDS, bOverFlow ) \ 83 if (nr < hppa::MAX_WORDS_IN_REGS) \ 84 { \ 85 sal_uInt32 *pDouble = (sal_uInt32 *)&(pFPR[nr++]); \ 86 pDouble[0] = *reinterpret_cast<sal_uInt32 *>( pSV ); \ 87 } \ 88 else \ 89 bOverFlow = true; \ 90 if (bOverFlow) \ 91 *pDS++ = *reinterpret_cast<sal_uInt32 *>( pSV ); 92 93 #define INSERT_DOUBLE( pSV, nr, pFPR, pDS, pStart, bOverFlow ) \ 94 if ( (nr < hppa::MAX_WORDS_IN_REGS) && (nr % 2) ) \ 95 { \ 96 ++nr; \ 97 } \ 98 if ( nr < hppa::MAX_WORDS_IN_REGS ) \ 99 { \ 100 sal_uInt32 *pDouble = (sal_uInt32 *)&(pFPR[nr+1]); \ 101 pDouble[0] = *reinterpret_cast<sal_uInt32 *>( pSV ); \ 102 pDouble[1] = *(reinterpret_cast<sal_uInt32 *>( pSV ) + 1); \ 103 nr+=2; \ 104 } \ 105 else \ 106 bOverFlow = true; \ 107 if ( bOverFlow ) \ 108 { \ 109 if ( (pDS - pStart) % 2) \ 110 ++pDS; \ 111 *pDS++ = reinterpret_cast<sal_uInt32 *>( pSV )[1]; \ 112 *pDS++ = reinterpret_cast<sal_uInt32 *>( pSV )[0]; \ 113 } 114 115 #define INSERT_INT16( pSV, nr, pGPR, pDS, bOverFlow ) \ 116 if ( nr < hppa::MAX_WORDS_IN_REGS ) \ 117 pGPR[nr++] = *reinterpret_cast<sal_uInt16 *>( pSV ); \ 118 else \ 119 bOverFlow = true; \ 120 if (bOverFlow) \ 121 *pDS++ = *reinterpret_cast<sal_uInt16 *>( pSV ); 122 123 #define INSERT_INT8( pSV, nr, pGPR, pDS, bOverFlow ) \ 124 if ( nr < hppa::MAX_WORDS_IN_REGS ) \ 125 pGPR[nr++] = *reinterpret_cast<sal_uInt8 *>( pSV ); \ 126 else \ 127 bOverFlow = true; \ 128 if (bOverFlow) \ 129 *pDS++ = *reinterpret_cast<sal_uInt8 *>( pSV ); 130 131 namespace hppa 132 { 133 bool is_complex_struct(const typelib_TypeDescription * type) 134 { 135 const typelib_CompoundTypeDescription * p 136 = reinterpret_cast< const typelib_CompoundTypeDescription * >(type); 137 for (sal_Int32 i = 0; i < p->nMembers; ++i) 138 { 139 if (p->ppTypeRefs[i]->eTypeClass == typelib_TypeClass_STRUCT || 140 p->ppTypeRefs[i]->eTypeClass == typelib_TypeClass_EXCEPTION) 141 { 142 typelib_TypeDescription * t = 0; 143 TYPELIB_DANGER_GET(&t, p->ppTypeRefs[i]); 144 bool b = is_complex_struct(t); 145 TYPELIB_DANGER_RELEASE(t); 146 if (b) { 147 return true; 148 } 149 } 150 else if (!bridges::cpp_uno::shared::isSimpleType(p->ppTypeRefs[i]->eTypeClass)) 151 return true; 152 } 153 if (p->pBaseTypeDescription != 0) 154 return is_complex_struct(&p->pBaseTypeDescription->aBase); 155 return false; 156 } 157 158 bool isRegisterReturn( typelib_TypeDescriptionReference *pTypeRef ) 159 { 160 if (bridges::cpp_uno::shared::isSimpleType(pTypeRef)) 161 return true; 162 else if (pTypeRef->eTypeClass == typelib_TypeClass_STRUCT || pTypeRef->eTypeClass == typelib_TypeClass_EXCEPTION) 163 { 164 typelib_TypeDescription * pTypeDescr = 0; 165 TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef ); 166 167 /* If the struct is larger than 8 bytes, then there is a buffer at r8 to stick the return value into */ 168 bool bRet = pTypeDescr->nSize <= 8 && !is_complex_struct(pTypeDescr); 169 170 TYPELIB_DANGER_RELEASE( pTypeDescr ); 171 return bRet; 172 } 173 return false; 174 } 175 } 176 177 178 namespace { 179 //======================================================================= 180 static void cpp_call( 181 bridges::cpp_uno::shared::UnoInterfaceProxy * pThis, 182 bridges::cpp_uno::shared::VtableSlot aVtableSlot, 183 typelib_TypeDescriptionReference * pReturnTypeRef, 184 sal_Int32 nParams, typelib_MethodParameter * pParams, 185 void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc ) 186 { 187 // max space for: [complex ret ptr], values|ptr ... 188 sal_uInt32 * pStack = (sal_uInt32 *)__builtin_alloca( 189 sizeof(sal_Int32) + ((nParams+2) * sizeof(sal_Int64)) ); 190 sal_uInt32 * pStackStart = pStack; 191 192 sal_uInt32 pGPR[hppa::MAX_GPR_REGS]; 193 double pFPR[hppa::MAX_SSE_REGS]; 194 sal_uInt32 nRegs=0; 195 196 // return 197 typelib_TypeDescription * pReturnTypeDescr = 0; 198 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef ); 199 OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" ); 200 201 void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion 202 bool bOverFlow = false; 203 bool bRegisterReturn = true; 204 205 if (pReturnTypeDescr) 206 { 207 208 bRegisterReturn = hppa::isRegisterReturn(pReturnTypeRef); 209 if (bRegisterReturn) 210 pCppReturn = pUnoReturn; // direct way for simple types 211 else 212 { 213 // complex return via ptr 214 pCppReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr ) 215 ? __builtin_alloca( pReturnTypeDescr->nSize ) 216 : pUnoReturn); // direct way 217 } 218 } 219 // push this 220 void * pAdjustedThisPtr = reinterpret_cast< void ** >(pThis->getCppI()) 221 + aVtableSlot.offset; 222 INSERT_INT32( &pAdjustedThisPtr, nRegs, pGPR, pStack, bOverFlow ); 223 224 // stack space 225 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" ); 226 // args 227 void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams ); 228 // indizes of values this have to be converted (interface conversion cpp<=>uno) 229 sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams); 230 // type descriptions for reconversions 231 typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams)); 232 233 sal_Int32 nTempIndizes = 0; 234 235 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) 236 { 237 const typelib_MethodParameter & rParam = pParams[nPos]; 238 typelib_TypeDescription * pParamTypeDescr = 0; 239 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef ); 240 241 if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr )) 242 { 243 uno_copyAndConvertData( pCppArgs[nPos] = alloca(8), pUnoArgs[nPos], 244 pParamTypeDescr, pThis->getBridge()->getUno2Cpp() ); 245 246 switch (pParamTypeDescr->eTypeClass) 247 { 248 case typelib_TypeClass_HYPER: 249 case typelib_TypeClass_UNSIGNED_HYPER: 250 #ifdef CMC_DEBUG 251 fprintf(stderr, "hyper is %llx\n", *((long long*)pCppArgs[nPos])); 252 #endif 253 INSERT_INT64( pCppArgs[nPos], nRegs, pGPR, pStack, pStackStart, bOverFlow ); 254 break; 255 case typelib_TypeClass_LONG: 256 case typelib_TypeClass_UNSIGNED_LONG: 257 case typelib_TypeClass_ENUM: 258 #ifdef CMC_DEBUG 259 fprintf(stderr, "long is %x\n", pCppArgs[nPos]); 260 #endif 261 INSERT_INT32( pCppArgs[nPos], nRegs, pGPR, pStack, bOverFlow ); 262 break; 263 case typelib_TypeClass_SHORT: 264 case typelib_TypeClass_CHAR: 265 case typelib_TypeClass_UNSIGNED_SHORT: 266 INSERT_INT16( pCppArgs[nPos], nRegs, pGPR, pStack, bOverFlow ); 267 break; 268 case typelib_TypeClass_BOOLEAN: 269 case typelib_TypeClass_BYTE: 270 INSERT_INT8( pCppArgs[nPos], nRegs, pGPR, pStack, bOverFlow ); 271 break; 272 case typelib_TypeClass_FLOAT: 273 INSERT_FLOAT( pCppArgs[nPos], nRegs, pFPR, pStack, bOverFlow ); 274 break; 275 case typelib_TypeClass_DOUBLE: 276 INSERT_DOUBLE( pCppArgs[nPos], nRegs, pFPR, pStack, pStackStart, bOverFlow ); 277 break; 278 default: 279 break; 280 } 281 // no longer needed 282 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 283 } 284 else // ptr to complex value | ref 285 { 286 if (! rParam.bIn) // is pure out 287 { 288 // cpp out is constructed mem, uno out is not! 289 uno_constructData( 290 pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ), 291 pParamTypeDescr ); 292 pTempIndizes[nTempIndizes] = nPos; // default constructed for cpp call 293 // will be released at reconversion 294 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 295 } 296 // is in/inout 297 else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr )) 298 { 299 uno_copyAndConvertData( 300 pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ), 301 pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() ); 302 303 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted 304 // will be released at reconversion 305 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 306 } 307 else // direct way 308 { 309 pCppArgs[nPos] = pUnoArgs[nPos]; 310 // no longer needed 311 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 312 } 313 INSERT_INT32( &(pCppArgs[nPos]), nRegs, pGPR, pStack, bOverFlow ); 314 } 315 } 316 317 try 318 { 319 callVirtualMethod( 320 pAdjustedThisPtr, aVtableSlot.index, 321 pCppReturn, pReturnTypeDescr, bRegisterReturn, 322 pStackStart, 323 (pStack - pStackStart), pGPR, pFPR); 324 325 // NO exception occured... 326 *ppUnoExc = 0; 327 328 // reconvert temporary params 329 for ( ; nTempIndizes--; ) 330 { 331 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 332 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes]; 333 334 if (pParams[nIndex].bIn) 335 { 336 if (pParams[nIndex].bOut) // inout 337 { 338 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value 339 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr, 340 pThis->getBridge()->getCpp2Uno() ); 341 } 342 } 343 else // pure out 344 { 345 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr, 346 pThis->getBridge()->getCpp2Uno() ); 347 } 348 // destroy temp cpp param => cpp: every param was constructed 349 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release ); 350 351 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 352 } 353 // return value 354 if (pCppReturn && pUnoReturn != pCppReturn) 355 { 356 uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr, 357 pThis->getBridge()->getCpp2Uno() ); 358 uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release ); 359 } 360 } 361 catch (...) 362 { 363 // fill uno exception 364 fillUnoException( CPPU_CURRENT_NAMESPACE::__cxa_get_globals()->caughtExceptions, *ppUnoExc, pThis->getBridge()->getCpp2Uno() ); 365 366 // temporary params 367 for ( ; nTempIndizes--; ) 368 { 369 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 370 // destroy temp cpp param => cpp: every param was constructed 371 uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], cpp_release ); 372 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] ); 373 } 374 375 // return type 376 if (pReturnTypeDescr) 377 TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); 378 } 379 } 380 } 381 382 namespace bridges { namespace cpp_uno { namespace shared { 383 384 void unoInterfaceProxyDispatch( 385 uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr, 386 void * pReturn, void * pArgs[], uno_Any ** ppException ) 387 { 388 // is my surrogate 389 bridges::cpp_uno::shared::UnoInterfaceProxy * pThis 390 = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI); 391 #if OSL_DEBUG_LEVEL > 0 392 typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr; 393 #endif 394 395 switch (pMemberDescr->eTypeClass) 396 { 397 case typelib_TypeClass_INTERFACE_ATTRIBUTE: 398 { 399 #if OSL_DEBUG_LEVEL > 0 400 // determine vtable call index 401 sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition; 402 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### member pos out of range!" ); 403 #endif 404 405 VtableSlot aVtableSlot( 406 getVtableSlot( 407 reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *> 408 (pMemberDescr))); 409 410 if (pReturn) 411 { 412 // dependent dispatch 413 cpp_call( 414 pThis, aVtableSlot, 415 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef, 416 0, 0, // no params 417 pReturn, pArgs, ppException ); 418 } 419 else 420 { 421 // is SET 422 typelib_MethodParameter aParam; 423 aParam.pTypeRef = 424 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef; 425 aParam.bIn = sal_True; 426 aParam.bOut = sal_False; 427 428 typelib_TypeDescriptionReference * pReturnTypeRef = 0; 429 OUString aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") ); 430 typelib_typedescriptionreference_new( 431 &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData ); 432 433 // dependent dispatch 434 aVtableSlot.index += 1; 435 cpp_call( 436 pThis, aVtableSlot, // get, then set method 437 pReturnTypeRef, 438 1, &aParam, 439 pReturn, pArgs, ppException ); 440 441 typelib_typedescriptionreference_release( pReturnTypeRef ); 442 } 443 444 break; 445 } 446 case typelib_TypeClass_INTERFACE_METHOD: 447 { 448 #if OSL_DEBUG_LEVEL > 0 449 // determine vtable call index 450 sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition; 451 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### member pos out of range!" ); 452 #endif 453 454 VtableSlot aVtableSlot( 455 getVtableSlot( 456 reinterpret_cast<typelib_InterfaceMethodTypeDescription const *> 457 (pMemberDescr))); 458 459 switch (aVtableSlot.index) 460 { 461 // standard calls 462 case 1: // acquire uno interface 463 (*pUnoI->acquire)( pUnoI ); 464 *ppException = 0; 465 break; 466 case 2: // release uno interface 467 (*pUnoI->release)( pUnoI ); 468 *ppException = 0; 469 break; 470 case 0: // queryInterface() opt 471 { 472 typelib_TypeDescription * pTD = 0; 473 TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() ); 474 if (pTD) 475 { 476 uno_Interface * pInterface = 0; 477 (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)( 478 pThis->getBridge()->getUnoEnv(), 479 (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD ); 480 481 if (pInterface) 482 { 483 ::uno_any_construct( 484 reinterpret_cast< uno_Any * >( pReturn ), 485 &pInterface, pTD, 0 ); 486 (*pInterface->release)( pInterface ); 487 TYPELIB_DANGER_RELEASE( pTD ); 488 *ppException = 0; 489 break; 490 } 491 492 TYPELIB_DANGER_RELEASE( pTD ); 493 } 494 } // else perform queryInterface() 495 default: 496 // dependent dispatch 497 cpp_call( 498 pThis, aVtableSlot, 499 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef, 500 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams, 501 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams, 502 pReturn, pArgs, ppException ); 503 } 504 break; 505 } 506 default: 507 { 508 ::com::sun::star::uno::RuntimeException aExc( 509 OUString( RTL_CONSTASCII_USTRINGPARAM("illegal member type description!") ), 510 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() ); 511 512 Type const & rExcType = ::getCppuType( &aExc ); 513 // binary identical null reference 514 ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 ); 515 } 516 } 517 } 518 519 } } } 520 521 /* vi:set tabstop=4 shiftwidth=4 expandtab: */ 522