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