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