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