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