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