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