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 #include <com/sun/star/uno/genfunc.hxx> 31 #include <typelib/typedescription.hxx> 32 #include <uno/data.h> 33 #include "bridges/cpp_uno/shared/bridge.hxx" 34 #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx" 35 #include "bridges/cpp_uno/shared/types.hxx" 36 #include "bridges/cpp_uno/shared/vtablefactory.hxx" 37 #include "share.hxx" 38 #include <sal/alloca.h> 39 40 using namespace com::sun::star::uno; 41 42 namespace 43 { 44 //================================================================================================== 45 static typelib_TypeClass cpp2uno_call( 46 bridges::cpp_uno::shared::CppInterfaceProxy * pThis, 47 const typelib_TypeDescription * pMemberTypeDescr, 48 typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return 49 sal_Int32 nParams, typelib_MethodParameter * pParams, 50 void ** pCallStack, 51 sal_Int64 * pRegisterReturn /* space for register return */ ) 52 { 53 // pCallStack: [ret ptr], this, params 54 char * pCppStack = (char *)pCallStack; 55 56 // return 57 typelib_TypeDescription * pReturnTypeDescr = 0; 58 if (pReturnTypeRef) 59 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef ); 60 61 void * pUnoReturn = 0; 62 void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need 63 64 if (pReturnTypeDescr) 65 { 66 if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr )) 67 pUnoReturn = pRegisterReturn; // direct way for simple types 68 else // complex return via ptr (pCppReturn) 69 { 70 pCppReturn = *(void**)pCppStack; 71 pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( 72 pReturnTypeDescr ) 73 ? alloca( pReturnTypeDescr->nSize ) 74 : pCppReturn); // direct way 75 pCppStack += sizeof( void* ); 76 } 77 } 78 // pop this 79 pCppStack += sizeof( void* ); 80 81 // stack space 82 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" ); 83 // parameters 84 void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams ); 85 void ** pCppArgs = pUnoArgs + nParams; 86 // indizes of values this have to be converted (interface conversion cpp<=>uno) 87 sal_Int32 * pTempIndizes = (sal_Int32 *)(pUnoArgs + (2 * nParams)); 88 // type descriptions for reconversions 89 typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams)); 90 91 sal_Int32 nTempIndizes = 0; 92 93 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) 94 { 95 const typelib_MethodParameter & rParam = pParams[nPos]; 96 typelib_TypeDescription * pParamTypeDescr = 0; 97 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef ); 98 99 if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr )) // value 100 { 101 pCppArgs[nPos] = pUnoArgs[nPos] = CPPU_CURRENT_NAMESPACE::adjustPointer(pCppStack, pParamTypeDescr); 102 switch (pParamTypeDescr->eTypeClass) 103 { 104 case typelib_TypeClass_HYPER: 105 case typelib_TypeClass_UNSIGNED_HYPER: 106 case typelib_TypeClass_DOUBLE: 107 { 108 if ((reinterpret_cast< long >(pCppStack) & 7) != 0) 109 { 110 OSL_ASSERT( sizeof (double) == sizeof (sal_Int64) ); 111 void * pDest = alloca( sizeof (sal_Int64) ); 112 *reinterpret_cast< sal_Int32 * >(pDest) = 113 *reinterpret_cast< sal_Int32 const * >(pCppStack); 114 *(reinterpret_cast< sal_Int32 * >(pDest) + 1) = 115 *(reinterpret_cast< sal_Int32 const * >(pCppStack) + 1); 116 pCppArgs[nPos] = pUnoArgs[nPos] = pDest; 117 } 118 pCppStack += sizeof (sal_Int32); // extra long 119 break; 120 } 121 } 122 // no longer needed 123 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 124 } 125 else // ptr to complex value | ref 126 { 127 pCppArgs[nPos] = *(void **)pCppStack; 128 129 if (! rParam.bIn) // is pure out 130 { 131 // uno out is unconstructed mem! 132 pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ); 133 pTempIndizes[nTempIndizes] = nPos; 134 // will be released at reconversion 135 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 136 } 137 // is in/inout 138 else if (bridges::cpp_uno::shared::relatesToInterfaceType( 139 pParamTypeDescr )) 140 { 141 uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ), 142 *(void **)pCppStack, pParamTypeDescr, 143 pThis->getBridge()->getCpp2Uno() ); 144 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted 145 // will be released at reconversion 146 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 147 } 148 else // direct way 149 { 150 pUnoArgs[nPos] = *(void **)pCppStack; 151 // no longer needed 152 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 153 } 154 } 155 pCppStack += sizeof(sal_Int32); // standard parameter length 156 } 157 158 // ExceptionHolder 159 uno_Any aUnoExc; // Any will be constructed by callee 160 uno_Any * pUnoExc = &aUnoExc; 161 162 // invoke uno dispatch call 163 (*pThis->getUnoI()->pDispatcher)(pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc ); 164 165 // in case an exception occured... 166 if (pUnoExc) 167 { 168 // destruct temporary in/inout params 169 for ( ; nTempIndizes--; ) 170 { 171 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 172 173 if (pParams[nIndex].bIn) // is in/inout => was constructed 174 uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], 0 ); 175 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] ); 176 } 177 if (pReturnTypeDescr) 178 TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); 179 CPPU_CURRENT_NAMESPACE::raiseException(&aUnoExc, pThis->getBridge()->getUno2Cpp() ); 180 // has to destruct the any 181 // is here for dummy 182 return typelib_TypeClass_VOID; 183 } 184 else // else no exception occured... 185 { 186 // temporary params 187 for ( ; nTempIndizes--; ) 188 { 189 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 190 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes]; 191 192 if (pParams[nIndex].bOut) // inout/out 193 { 194 // convert and assign 195 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release ); 196 uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr, 197 pThis->getBridge()->getUno2Cpp() ); 198 } 199 // destroy temp uno param 200 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); 201 202 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 203 } 204 // return 205 if (pCppReturn) // has complex return 206 { 207 if (pUnoReturn != pCppReturn) // needs reconversion 208 { 209 uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr, 210 pThis->getBridge()->getUno2Cpp() ); 211 // destroy temp uno return 212 uno_destructData( pUnoReturn, pReturnTypeDescr, 0 ); 213 } 214 // complex return ptr is set to eax 215 *(void **)pRegisterReturn = pCppReturn; 216 } 217 if (pReturnTypeDescr) 218 { 219 typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass; 220 TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); 221 return eRet; 222 } 223 else 224 return typelib_TypeClass_VOID; 225 } 226 } 227 228 229 //================================================================================================== 230 static typelib_TypeClass cpp_mediate( 231 sal_Int32 nFunctionIndex, 232 sal_Int32 nVtableOffset, 233 void ** pCallStack, 234 sal_Int64 * pRegisterReturn /* space for register return */ ) 235 { 236 OSL_ENSURE( sizeof(sal_Int32)==sizeof(void *), "### unexpected!" ); 237 238 // pCallStack: this, params 239 // eventual [ret*] lies at pCallStack -1 240 // so count down pCallStack by one to keep it simple 241 // pCallStack: this, params 242 // eventual [ret*] lies at pCallStack -1 243 // so count down pCallStack by one to keep it simple 244 bridges::cpp_uno::shared::CppInterfaceProxy * pCppI 245 = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( 246 static_cast< char * >(*pCallStack) - nVtableOffset); 247 if ((nFunctionIndex & 0x80000000) != 0) { 248 nFunctionIndex &= 0x7FFFFFFF; 249 --pCallStack; 250 } 251 252 typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr(); 253 254 OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex, 255 "### illegal vtable index!" ); 256 if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex) 257 { 258 throw RuntimeException( rtl::OUString::createFromAscii("illegal vtable index!"), (XInterface *)pCppI ); 259 } 260 261 // determine called method 262 sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex]; 263 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!" ); 264 265 TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] ); 266 267 #if defined BRIDGES_DEBUG 268 OString cstr( OUStringToOString( aMemberDescr.get()->pTypeName, RTL_TEXTENCODING_ASCII_US ) ); 269 fprintf( stderr, "calling %s, nFunctionIndex=%d\n", cstr.getStr(), nFunctionIndex ); 270 #endif 271 272 typelib_TypeClass eRet; 273 switch (aMemberDescr.get()->eTypeClass) 274 { 275 case typelib_TypeClass_INTERFACE_ATTRIBUTE: 276 { 277 if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex) 278 { 279 // is GET method 280 eRet = cpp2uno_call( 281 pCppI, aMemberDescr.get(), 282 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef, 283 0, 0, // no params 284 pCallStack, pRegisterReturn ); 285 } 286 else 287 { 288 // is SET method 289 typelib_MethodParameter aParam; 290 aParam.pTypeRef = 291 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef; 292 aParam.bIn = sal_True; 293 aParam.bOut = sal_False; 294 295 eRet = cpp2uno_call( 296 pCppI, aMemberDescr.get(), 297 0, // indicates void return 298 1, &aParam, 299 pCallStack, pRegisterReturn ); 300 } 301 break; 302 } 303 case typelib_TypeClass_INTERFACE_METHOD: 304 { 305 // is METHOD 306 switch (nFunctionIndex) 307 { 308 case 1: // acquire() 309 pCppI->acquireProxy(); // non virtual call! 310 eRet = typelib_TypeClass_VOID; 311 break; 312 case 2: // release() 313 pCppI->releaseProxy(); // non virtual call! 314 eRet = typelib_TypeClass_VOID; 315 break; 316 case 0: // queryInterface() opt 317 { 318 typelib_TypeDescription * pTD = 0; 319 TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pCallStack[2] )->getTypeLibType() ); 320 if (pTD) 321 { 322 XInterface * pInterface = 0; 323 (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)( 324 pCppI->getBridge()->getCppEnv(), 325 (void **)&pInterface, pCppI->getOid().pData, (typelib_InterfaceTypeDescription *)pTD ); 326 327 if (pInterface) 328 { 329 ::uno_any_construct( 330 reinterpret_cast< uno_Any * >( pCallStack[0] ), 331 &pInterface, pTD, cpp_acquire ); 332 pInterface->release(); 333 TYPELIB_DANGER_RELEASE( pTD ); 334 *(void **)pRegisterReturn = pCallStack[0]; 335 eRet = typelib_TypeClass_ANY; 336 break; 337 } 338 TYPELIB_DANGER_RELEASE( pTD ); 339 } 340 } // else perform queryInterface() 341 default: 342 eRet = cpp2uno_call( 343 pCppI, aMemberDescr.get(), 344 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef, 345 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams, 346 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams, 347 pCallStack, pRegisterReturn ); 348 } 349 break; 350 } 351 default: 352 { 353 throw RuntimeException(rtl::OUString::createFromAscii("no member description found!"), (XInterface *)pCppI ); 354 // is here for dummy 355 eRet = typelib_TypeClass_VOID; 356 } 357 } 358 return eRet; 359 } 360 361 362 363 //================================================================================================== 364 /** 365 * is called on incoming vtable calls 366 * (called by asm snippets) 367 */ 368 static void cpp_vtable_call() 369 { 370 volatile sal_Int64 nRegReturn; 371 int nFunctionIndex; 372 void** pCallStack; 373 int vTableOffset; 374 375 __asm__( "st %%i0, %0\n\t" 376 "st %%i1, %1\n\t" 377 "st %%i2, %2\n\t" 378 : : "m"(nFunctionIndex), "m"(pCallStack), "m"(vTableOffset) ); 379 380 // fprintf(stderr,"cpp_mediate nFunctionIndex=%x\n",nFunctionIndex); 381 // fflush(stderr); 382 383 sal_Bool bComplex = nFunctionIndex & 0x80000000 ? sal_True : sal_False; 384 typelib_TypeClass aType = 385 cpp_mediate( nFunctionIndex, vTableOffset, pCallStack+17, (sal_Int64*)&nRegReturn ); 386 387 switch( aType ) 388 { 389 case typelib_TypeClass_BOOLEAN: 390 case typelib_TypeClass_BYTE: 391 __asm__( "ld %0, %%l0\n\t" 392 "ldsb [%%l0], %%i0\n" 393 : : "m"(&nRegReturn) ); 394 break; 395 case typelib_TypeClass_CHAR: 396 case typelib_TypeClass_SHORT: 397 case typelib_TypeClass_UNSIGNED_SHORT: 398 __asm__( "ld %0, %%l0\n\t" 399 "ldsh [%%l0], %%i0\n" 400 : : "m"(&nRegReturn) ); 401 break; 402 case typelib_TypeClass_HYPER: 403 case typelib_TypeClass_UNSIGNED_HYPER: 404 405 __asm__( "ld %0, %%l0\n\t" 406 "ld [%%l0], %%i0\n\t" 407 "ld %1, %%l0\n\t" 408 "ld [%%l0], %%i1\n\t" 409 : : "m"(&nRegReturn), "m"(((long*)&nRegReturn) +1) ); 410 411 break; 412 case typelib_TypeClass_FLOAT: 413 __asm__( "ld %0, %%l0\n\t" 414 "ld [%%l0], %%f0\n" 415 : : "m"(&nRegReturn) ); 416 break; 417 case typelib_TypeClass_DOUBLE: 418 __asm__( "ld %0, %%l0\n\t" 419 "ldd [%%l0], %%f0\n" 420 : : "m"(&nRegReturn) ); 421 break; 422 case typelib_TypeClass_VOID: 423 break; 424 default: 425 __asm__( "ld %0, %%l0\n\t" 426 "ld [%%l0], %%i0\n" 427 : : "m"(&nRegReturn) ); 428 break; 429 } 430 431 if( bComplex ) 432 { 433 __asm__( "add %i7, 4, %i7\n\t" ); 434 // after call to complex return valued funcion there is an unimp instruction 435 } 436 437 } 438 //__________________________________________________________________________________________________ 439 440 int const codeSnippetSize = 56; 441 unsigned char * codeSnippet( 442 unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset, 443 bool simpleRetType) 444 { 445 sal_uInt32 index = functionIndex; 446 if (!simpleRetType) { 447 index |= 0x80000000; 448 } 449 unsigned int * p = reinterpret_cast< unsigned int * >(code); 450 OSL_ASSERT(sizeof (unsigned int) == 4); 451 // st %o0, [%sp+68]: 452 *p++ = 0xD023A044; 453 // st %o1, [%sp+72]: 454 *p++ = 0xD223A048; 455 // st %o2, [%sp+76]: 456 *p++ = 0xD423A04C; 457 // st %o3, [%sp+80]: 458 *p++ = 0xD623A050; 459 // st %o4, [%sp+84]: 460 *p++ = 0xD823A054; 461 // st %o5, [%sp+88]: 462 *p++ = 0xDA23A058; 463 // sethi %hi(index), %o0: 464 *p++ = 0x11000000 | (index >> 10); 465 // or %o0, %lo(index), %o0: 466 *p++ = 0x90122000 | (index & 0x3FF); 467 // sethi %hi(vtableOffset), %o2: 468 *p++ = 0x15000000 | (vtableOffset >> 10); 469 // or %o2, %lo(vtableOffset), %o2: 470 *p++ = 0x9412A000 | (vtableOffset & 0x3FF); 471 // sethi %hi(cpp_vtable_call), %o3: 472 *p++ = 0x17000000 | (reinterpret_cast< unsigned int >(cpp_vtable_call) >> 10); 473 // or %o3, %lo(cpp_vtable_call), %o3: 474 *p++ = 0x9612E000 | (reinterpret_cast< unsigned int >(cpp_vtable_call) & 0x3FF); 475 // jmpl %o3, %g0: 476 *p++ = 0x81C2C000; 477 // mov %sp, %o1: 478 *p++ = 0x9210000E; 479 OSL_ASSERT( 480 reinterpret_cast< unsigned char * >(p) - code <= codeSnippetSize); 481 return code + codeSnippetSize; 482 } 483 484 } //end of namespace 485 486 struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; 487 488 bridges::cpp_uno::shared::VtableFactory::Slot * 489 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) 490 { 491 return static_cast< Slot * >(block) + 2; 492 } 493 494 sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize( 495 sal_Int32 slotCount) 496 { 497 return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize; 498 } 499 500 bridges::cpp_uno::shared::VtableFactory::Slot * 501 bridges::cpp_uno::shared::VtableFactory::initializeBlock( 502 void * block, sal_Int32 slotCount) 503 { 504 Slot * slots = mapBlockToVtable(block); 505 slots[-2].fn = 0; //null 506 slots[-1].fn = 0; //destructor 507 return slots + slotCount; 508 } 509 510 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions( 511 Slot ** slots, unsigned char * code, 512 typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset, 513 sal_Int32 functionCount, sal_Int32 vTableOffset) 514 { 515 (*slots) -= functionCount; 516 Slot * s = *slots; 517 for (sal_Int32 i = 0; i < type->nMembers; ++i) { 518 typelib_TypeDescription * member = 0; 519 TYPELIB_DANGER_GET(&member, type->ppMembers[i]); 520 OSL_ASSERT(member != 0); 521 switch (member->eTypeClass) { 522 case typelib_TypeClass_INTERFACE_ATTRIBUTE: 523 // Getter: 524 (s++)->fn = code; 525 code = codeSnippet( 526 code, functionOffset++, vTableOffset, 527 bridges::cpp_uno::shared::isSimpleType( 528 reinterpret_cast< 529 typelib_InterfaceAttributeTypeDescription * >( 530 member)->pAttributeTypeRef)); 531 // Setter: 532 if (!reinterpret_cast< 533 typelib_InterfaceAttributeTypeDescription * >( 534 member)->bReadOnly) 535 { 536 (s++)->fn = code; 537 code = codeSnippet(code, functionOffset++, vTableOffset, true); 538 } 539 break; 540 541 case typelib_TypeClass_INTERFACE_METHOD: 542 (s++)->fn = code; 543 code = codeSnippet( 544 code, functionOffset++, vTableOffset, 545 bridges::cpp_uno::shared::isSimpleType( 546 reinterpret_cast< 547 typelib_InterfaceMethodTypeDescription * >( 548 member)->pReturnTypeRef)); 549 break; 550 551 default: 552 OSL_ASSERT(false); 553 break; 554 } 555 TYPELIB_DANGER_RELEASE(member); 556 } 557 return code; 558 } 559 560 void bridges::cpp_uno::shared::VtableFactory::flushCode( 561 unsigned char const *, unsigned char const *) 562 { 563 //TODO: IZ 25819 flush the instruction cache (there probably is OS support for this) 564 } 565