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