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 31 #include <sal/alloca.h> 32 33 #include <com/sun/star/uno/genfunc.hxx> 34 #include "com/sun/star/uno/RuntimeException.hpp" 35 #include <uno/data.h> 36 #include <typelib/typedescription.hxx> 37 38 #include "bridges/cpp_uno/shared/bridge.hxx" 39 #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx" 40 #include "bridges/cpp_uno/shared/types.hxx" 41 #include "bridges/cpp_uno/shared/vtablefactory.hxx" 42 43 #include "share.hxx" 44 45 using namespace ::com::sun::star::uno; 46 47 namespace 48 { 49 50 //================================================================================================== 51 static typelib_TypeClass cpp2uno_call( 52 bridges::cpp_uno::shared::CppInterfaceProxy * pThis, 53 const typelib_TypeDescription * pMemberTypeDescr, 54 typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return 55 sal_Int32 nParams, typelib_MethodParameter * pParams, 56 void ** pCallStack, 57 sal_Int64 * pRegisterReturn /* space for register return */ ) 58 { 59 // pCallStack: ret, [return ptr], this, params 60 char * pCppStack = (char *)(pCallStack +1); 61 62 // return 63 typelib_TypeDescription * pReturnTypeDescr = 0; 64 if (pReturnTypeRef) 65 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef ); 66 67 void * pUnoReturn = 0; 68 void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need 69 70 if (pReturnTypeDescr) 71 { 72 if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr )) 73 { 74 pUnoReturn = pRegisterReturn; // direct way for simple types 75 } 76 else // complex return via ptr (pCppReturn) 77 { 78 pCppReturn = *(void **)pCppStack; 79 pCppStack += sizeof(void *); 80 81 pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( 82 pReturnTypeDescr ) 83 ? alloca( pReturnTypeDescr->nSize ) 84 : pCppReturn); // direct way 85 } 86 } 87 // pop this 88 pCppStack += sizeof( void* ); 89 90 // stack space 91 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" ); 92 // parameters 93 void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams ); 94 void ** pCppArgs = pUnoArgs + nParams; 95 // indizes of values this have to be converted (interface conversion cpp<=>uno) 96 sal_Int32 * pTempIndizes = (sal_Int32 *)(pUnoArgs + (2 * nParams)); 97 // type descriptions for reconversions 98 typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams)); 99 100 sal_Int32 nTempIndizes = 0; 101 102 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) 103 { 104 const typelib_MethodParameter & rParam = pParams[nPos]; 105 typelib_TypeDescription * pParamTypeDescr = 0; 106 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef ); 107 108 if (!rParam.bOut 109 && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr )) 110 // value 111 { 112 pCppArgs[nPos] = pCppStack; 113 pUnoArgs[nPos] = pCppStack; 114 switch (pParamTypeDescr->eTypeClass) 115 { 116 case typelib_TypeClass_HYPER: 117 case typelib_TypeClass_UNSIGNED_HYPER: 118 case typelib_TypeClass_DOUBLE: 119 pCppStack += sizeof(sal_Int32); // extra long 120 } 121 // no longer needed 122 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 123 } 124 else // ptr to complex value | ref 125 { 126 pCppArgs[nPos] = *(void **)pCppStack; 127 128 if (! rParam.bIn) // is pure out 129 { 130 // uno out is unconstructed mem! 131 pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ); 132 pTempIndizes[nTempIndizes] = nPos; 133 // will be released at reconversion 134 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 135 } 136 // is in/inout 137 else if (bridges::cpp_uno::shared::relatesToInterfaceType( 138 pParamTypeDescr )) 139 { 140 uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ), 141 *(void **)pCppStack, pParamTypeDescr, 142 pThis->getBridge()->getCpp2Uno() ); 143 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted 144 // will be released at reconversion 145 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 146 } 147 else // direct way 148 { 149 pUnoArgs[nPos] = *(void **)pCppStack; 150 // no longer needed 151 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 152 } 153 } 154 pCppStack += sizeof(sal_Int32); // standard parameter length 155 } 156 157 // ExceptionHolder 158 uno_Any aUnoExc; // Any will be constructed by callee 159 uno_Any * pUnoExc = &aUnoExc; 160 161 // invoke uno dispatch call 162 (*pThis->getUnoI()->pDispatcher)( 163 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 180 CPPU_CURRENT_NAMESPACE::raiseException( 181 &aUnoExc, pThis->getBridge()->getUno2Cpp() ); 182 // has to destruct the any 183 // is here for dummy 184 return typelib_TypeClass_VOID; 185 } 186 else // else no exception occured... 187 { 188 // temporary params 189 for ( ; nTempIndizes--; ) 190 { 191 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 192 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes]; 193 194 if (pParams[nIndex].bOut) // inout/out 195 { 196 // convert and assign 197 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release ); 198 uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr, 199 pThis->getBridge()->getUno2Cpp() ); 200 } 201 // destroy temp uno param 202 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); 203 204 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 205 } 206 // return 207 if (pCppReturn) // has complex return 208 { 209 if (pUnoReturn != pCppReturn) // needs reconversion 210 { 211 uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr, 212 pThis->getBridge()->getUno2Cpp() ); 213 // destroy temp uno return 214 uno_destructData( pUnoReturn, pReturnTypeDescr, 0 ); 215 } 216 // complex return ptr is set to eax 217 *(void **)pRegisterReturn = pCppReturn; 218 } 219 if (pReturnTypeDescr) 220 { 221 typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass; 222 TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); 223 return eRet; 224 } 225 else 226 return typelib_TypeClass_VOID; 227 } 228 } 229 230 231 //================================================================================================== 232 static typelib_TypeClass cpp_mediate( 233 sal_Int32 nFunctionIndex, 234 sal_Int32 nVtableOffset, 235 void ** pCallStack, 236 sal_Int64 * pRegisterReturn /* space for register return */ ) 237 { 238 OSL_ENSURE( sizeof(sal_Int32)==sizeof(void *), "### unexpected!" ); 239 240 // pCallStack: ret adr, [ret *], this, params 241 void * pThis; 242 if( nFunctionIndex & 0x80000000 ) 243 { 244 nFunctionIndex &= 0x7fffffff; 245 pThis = pCallStack[2]; 246 } 247 else 248 { 249 pThis = pCallStack[1]; 250 } 251 pThis = static_cast< char * >(pThis) - nVtableOffset; 252 bridges::cpp_uno::shared::CppInterfaceProxy * pCppI 253 = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( 254 pThis); 255 256 typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr(); 257 258 OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!" ); 259 if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex) 260 { 261 throw RuntimeException( 262 rtl::OUString::createFromAscii("illegal vtable index!"), 263 (XInterface *)pThis ); 264 } 265 266 // determine called method 267 sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex]; 268 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!" ); 269 270 TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] ); 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[3] )->getTypeLibType() ); 320 if (pTD) 321 { 322 XInterface * pInterface = 0; 323 (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)( 324 pCppI->getBridge()->getCppEnv(), 325 (void **)&pInterface, pCppI->getOid().pData, 326 (typelib_InterfaceTypeDescription *)pTD ); 327 328 if (pInterface) 329 { 330 ::uno_any_construct( 331 reinterpret_cast< uno_Any * >( pCallStack[1] ), 332 &pInterface, pTD, cpp_acquire ); 333 pInterface->release(); 334 TYPELIB_DANGER_RELEASE( pTD ); 335 *(void **)pRegisterReturn = pCallStack[1]; 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( 355 rtl::OUString::createFromAscii("no member description found!"), 356 (XInterface *)pThis ); 357 // is here for dummy 358 eRet = typelib_TypeClass_VOID; 359 } 360 } 361 362 return eRet; 363 } 364 365 //================================================================================================== 366 /** 367 * is called on incoming vtable calls 368 * (called by asm snippets) 369 */ 370 static void cpp_vtable_call( 371 int nFunctionIndex, int nVtableOffset, void** pCallStack ) 372 __attribute__((regparm(3))); 373 374 void cpp_vtable_call( int nFunctionIndex, int nVtableOffset, void** pCallStack ) 375 { 376 volatile long nRegReturn[2]; 377 typelib_TypeClass aType = cpp_mediate( 378 nFunctionIndex, nVtableOffset, pCallStack, (sal_Int64*)nRegReturn ); 379 380 switch( aType ) 381 { 382 case typelib_TypeClass_HYPER: 383 case typelib_TypeClass_UNSIGNED_HYPER: 384 __asm__( "movl %1, %%edx\n\t" 385 "movl %0, %%eax\n" 386 : : "m"(nRegReturn[0]), "m"(nRegReturn[1]) ); 387 break; 388 case typelib_TypeClass_FLOAT: 389 __asm__( "flds %0\n\t" 390 "fstp %%st(0)\n\t" 391 "flds %0\n" 392 : : "m"(*(float *)nRegReturn) ); 393 break; 394 case typelib_TypeClass_DOUBLE: 395 __asm__( "fldl %0\n\t" 396 "fstp %%st(0)\n\t" 397 "fldl %0\n" 398 : : "m"(*(double *)nRegReturn) ); 399 break; 400 // case typelib_TypeClass_UNSIGNED_SHORT: 401 // case typelib_TypeClass_SHORT: 402 // __asm__( "movswl %0, %%eax\n" 403 // : : "m"(nRegReturn) ); 404 // break; 405 default: 406 __asm__( "movl %0, %%eax\n" 407 : : "m"(nRegReturn[0]) ); 408 break; 409 } 410 } 411 412 413 //================================================================================================== 414 int const codeSnippetSize = 20; 415 416 unsigned char * codeSnippet( 417 unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset, 418 bool simpleRetType) 419 { 420 if (!simpleRetType) { 421 functionIndex |= 0x80000000; 422 } 423 unsigned char * p = code; 424 OSL_ASSERT(sizeof (sal_Int32) == 4); 425 // mov function_index, %eax: 426 *p++ = 0xB8; 427 *reinterpret_cast< sal_Int32 * >(p) = functionIndex; 428 p += sizeof (sal_Int32); 429 // mov vtable_offset, %edx: 430 *p++ = 0xBA; 431 *reinterpret_cast< sal_Int32 * >(p) = vtableOffset; 432 p += sizeof (sal_Int32); 433 // mov %esp, %ecx: 434 *p++ = 0x89; 435 *p++ = 0xE1; 436 // jmp cpp_vtable_call: 437 *p++ = 0xE9; 438 *reinterpret_cast< sal_Int32 * >(p) 439 = ((unsigned char *) cpp_vtable_call) - p - sizeof (sal_Int32); 440 p += sizeof (sal_Int32); 441 OSL_ASSERT(p - code <= codeSnippetSize); 442 return code + codeSnippetSize; 443 } 444 445 } 446 447 struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; 448 449 bridges::cpp_uno::shared::VtableFactory::Slot * 450 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) 451 { 452 return static_cast< Slot * >(block) + 2; 453 } 454 455 sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize( 456 sal_Int32 slotCount) 457 { 458 return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize; 459 } 460 461 bridges::cpp_uno::shared::VtableFactory::Slot * 462 bridges::cpp_uno::shared::VtableFactory::initializeBlock( 463 void * block, sal_Int32 slotCount) 464 { 465 Slot * slots = mapBlockToVtable(block); 466 slots[-2].fn = 0; 467 slots[-1].fn = 0; 468 return slots + slotCount; 469 } 470 471 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions( 472 Slot ** slots, unsigned char * code, 473 typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset, 474 sal_Int32 functionCount, sal_Int32 vtableOffset) 475 { 476 (*slots) -= functionCount; 477 Slot * s = *slots; 478 for (sal_Int32 i = 0; i < type->nMembers; ++i) { 479 typelib_TypeDescription * member = 0; 480 TYPELIB_DANGER_GET(&member, type->ppMembers[i]); 481 OSL_ASSERT(member != 0); 482 switch (member->eTypeClass) { 483 case typelib_TypeClass_INTERFACE_ATTRIBUTE: 484 // Getter: 485 (s++)->fn = code; 486 code = codeSnippet( 487 code, functionOffset++, vtableOffset, 488 bridges::cpp_uno::shared::isSimpleType( 489 reinterpret_cast< 490 typelib_InterfaceAttributeTypeDescription * >( 491 member)->pAttributeTypeRef)); 492 // Setter: 493 if (!reinterpret_cast< 494 typelib_InterfaceAttributeTypeDescription * >( 495 member)->bReadOnly) 496 { 497 (s++)->fn = code; 498 code = codeSnippet(code, functionOffset++, vtableOffset, true); 499 } 500 break; 501 502 case typelib_TypeClass_INTERFACE_METHOD: 503 (s++)->fn = code; 504 code = codeSnippet( 505 code, functionOffset++, vtableOffset, 506 bridges::cpp_uno::shared::isSimpleType( 507 reinterpret_cast< 508 typelib_InterfaceMethodTypeDescription * >( 509 member)->pReturnTypeRef)); 510 break; 511 512 default: 513 OSL_ASSERT(false); 514 break; 515 } 516 TYPELIB_DANGER_RELEASE(member); 517 } 518 return code; 519 } 520 521 void bridges::cpp_uno::shared::VtableFactory::flushCode( 522 unsigned char const *, unsigned char const *) 523 {} 524