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