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