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 "com/sun/star/uno/Sequence.hxx" 34 #include <uno/data.h> 35 #include <typelib/typedescription.hxx> 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 44 #include "boost/static_assert.hpp" 45 #include <stdio.h> 46 47 using namespace ::com::sun::star::uno; 48 49 namespace 50 { 51 52 //================================================================================================== 53 void cpp2uno_call( 54 bridges::cpp_uno::shared::CppInterfaceProxy * pThis, 55 const typelib_TypeDescription * pMemberTypeDescr, 56 typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return 57 sal_Int32 nParams, typelib_MethodParameter * pParams, 58 void ** pCallStack, 59 void * pReturnValue ) 60 { 61 // pCallStack: ret, [return ptr], this, params 62 char * pCppStack = (char *)(pCallStack +1); 63 64 // return 65 typelib_TypeDescription * pReturnTypeDescr = 0; 66 if (pReturnTypeRef) 67 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef ); 68 69 void * pUnoReturn = 0; 70 void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need 71 72 if (pReturnTypeDescr) 73 { 74 // xxx todo: test PolyStructy<STRUCT<long>> foo() 75 if (CPPU_CURRENT_NAMESPACE::isSimpleReturnType( pReturnTypeDescr )) 76 { 77 pUnoReturn = pReturnValue; // direct way for simple types 78 } 79 else // complex return via ptr (pCppReturn) 80 { 81 pCppReturn = *(void **)pCppStack; 82 pCppStack += sizeof(void *); 83 pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( 84 pReturnTypeDescr ) 85 ? alloca( pReturnTypeDescr->nSize ) 86 : pCppReturn); // direct way 87 } 88 } 89 // pop this 90 pCppStack += sizeof( void* ); 91 92 // stack space 93 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### 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 cpp<=>uno) 98 sal_Int32 * pTempIndizes = (sal_Int32 *)(pUnoArgs + (2 * nParams)); 99 // type descriptions for reconversions 100 typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams)); 101 102 sal_Int32 nTempIndizes = 0; 103 104 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) 105 { 106 const typelib_MethodParameter & rParam = pParams[nPos]; 107 typelib_TypeDescription * pParamTypeDescr = 0; 108 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef ); 109 110 if (!rParam.bOut 111 && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr )) 112 // value 113 { 114 pCppArgs[nPos] = pCppStack; 115 pUnoArgs[nPos] = pCppStack; 116 switch (pParamTypeDescr->eTypeClass) 117 { 118 case typelib_TypeClass_HYPER: 119 case typelib_TypeClass_UNSIGNED_HYPER: 120 case typelib_TypeClass_DOUBLE: 121 pCppStack += sizeof(sal_Int32); // extra long 122 default: 123 break; 124 } 125 // no longer needed 126 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 127 } 128 else // ptr to complex value | ref 129 { 130 pCppArgs[nPos] = *(void **)pCppStack; 131 132 if (! rParam.bIn) // is pure out 133 { 134 // uno out is unconstructed mem! 135 pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ); 136 pTempIndizes[nTempIndizes] = nPos; 137 // will be released at reconversion 138 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 139 } 140 // is in/inout 141 else if (bridges::cpp_uno::shared::relatesToInterfaceType( 142 pParamTypeDescr )) 143 { 144 uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ), 145 *(void **)pCppStack, pParamTypeDescr, 146 pThis->getBridge()->getCpp2Uno() ); 147 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted 148 // will be released at reconversion 149 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 150 } 151 else // direct way 152 { 153 pUnoArgs[nPos] = *(void **)pCppStack; 154 // no longer needed 155 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 156 } 157 } 158 pCppStack += sizeof(sal_Int32); // standard parameter length 159 } 160 161 // ExceptionHolder 162 uno_Any aUnoExc; // Any will be constructed by callee 163 uno_Any * pUnoExc = &aUnoExc; 164 165 // invoke uno dispatch call 166 (*pThis->getUnoI()->pDispatcher)( 167 pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc ); 168 169 // in case an exception occured... 170 if (pUnoExc) 171 { 172 // destruct temporary in/inout params 173 for ( ; nTempIndizes--; ) 174 { 175 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 176 177 if (pParams[nIndex].bIn) // is in/inout => was constructed 178 uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], 0 ); 179 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] ); 180 } 181 if (pReturnTypeDescr) 182 TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); 183 184 CPPU_CURRENT_NAMESPACE::raiseException( 185 &aUnoExc, pThis->getBridge()->getUno2Cpp() ); 186 // has to destruct the any 187 } 188 else // else no exception occured... 189 { 190 // temporary params 191 for ( ; nTempIndizes--; ) 192 { 193 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 194 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes]; 195 196 if (pParams[nIndex].bOut) // inout/out 197 { 198 // convert and assign 199 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release ); 200 uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr, 201 pThis->getBridge()->getUno2Cpp() ); 202 } 203 // destroy temp uno param 204 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); 205 206 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 207 } 208 // return 209 if (pCppReturn) // has complex return 210 { 211 if (pUnoReturn != pCppReturn) // needs reconversion 212 { 213 uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr, 214 pThis->getBridge()->getUno2Cpp() ); 215 // destroy temp uno return 216 uno_destructData( pUnoReturn, pReturnTypeDescr, 0 ); 217 } 218 if (pReturnValue != pCppReturn) { 219 // complex return ptr is set to eax if return value 220 // is not transferred via eax[/edx]: 221 *static_cast< void ** >(pReturnValue) = pCppReturn; 222 } 223 } 224 if (pReturnTypeDescr) 225 { 226 TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); 227 } 228 } 229 } 230 231 232 //================================================================================================== 233 extern "C" void cpp_vtable_call( 234 int nFunctionIndex, int nVtableOffset, void** pCallStack, 235 void * pReturnValue ) 236 { 237 OSL_ENSURE( sizeof(sal_Int32)==sizeof(void *), "### unexpected!" ); 238 239 // pCallStack: ret adr, [ret *], this, params 240 void * pThis; 241 if( nFunctionIndex & 0x80000000 ) 242 { 243 nFunctionIndex &= 0x7fffffff; 244 pThis = pCallStack[2]; 245 } 246 else 247 { 248 pThis = pCallStack[1]; 249 } 250 pThis = static_cast< char * >(pThis) - nVtableOffset; 251 bridges::cpp_uno::shared::CppInterfaceProxy * pCppI 252 = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( 253 pThis); 254 #if OSL_DEBUG_LEVEL > 1 255 fprintf( stderr, "%p %p %p pThis=%p, pCppI=%p, function index=%d, vtable offset=%d\n", pCallStack[0], pCallStack[1], pCallStack[2], pThis, pCppI, nFunctionIndex, nVtableOffset ); 256 #endif 257 typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr(); 258 #if OSL_DEBUG_LEVEL > 1 259 fprintf( stderr, "name=%s\n", rtl::OUStringToOString(pTypeDescr->aBase.pTypeName, RTL_TEXTENCODING_UTF8).getStr() ); 260 #endif 261 OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!" ); 262 if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex) 263 { 264 throw RuntimeException( 265 rtl::OUString::createFromAscii("illegal vtable index!"), 266 (XInterface *)pThis ); 267 } 268 269 // determine called method 270 sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex]; 271 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!" ); 272 273 TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] ); 274 #if OSL_DEBUG_LEVEL > 1 275 fprintf(stderr, "calling %s\n", rtl::OUStringToOString(aMemberDescr.get()->pTypeName, RTL_TEXTENCODING_UTF8).getStr()); 276 #endif 277 switch (aMemberDescr.get()->eTypeClass) 278 { 279 case typelib_TypeClass_INTERFACE_ATTRIBUTE: 280 { 281 if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex) 282 { 283 // is GET method 284 cpp2uno_call( 285 pCppI, aMemberDescr.get(), 286 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef, 287 0, 0, // no params 288 pCallStack, pReturnValue ); 289 } 290 else 291 { 292 // is SET method 293 typelib_MethodParameter aParam; 294 aParam.pTypeRef = 295 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef; 296 aParam.bIn = sal_True; 297 aParam.bOut = sal_False; 298 299 cpp2uno_call( 300 pCppI, aMemberDescr.get(), 301 0, // indicates void return 302 1, &aParam, 303 pCallStack, pReturnValue ); 304 } 305 break; 306 } 307 case typelib_TypeClass_INTERFACE_METHOD: 308 { 309 // is METHOD 310 switch (nFunctionIndex) 311 { 312 case 1: // acquire() 313 pCppI->acquireProxy(); // non virtual call! 314 break; 315 case 2: // release() 316 pCppI->releaseProxy(); // non virtual call! 317 break; 318 case 0: // queryInterface() opt 319 { 320 typelib_TypeDescription * pTD = 0; 321 TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pCallStack[3] )->getTypeLibType() ); 322 if (pTD) 323 { 324 XInterface * pInterface = 0; 325 (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)( 326 pCppI->getBridge()->getCppEnv(), 327 (void **)&pInterface, pCppI->getOid().pData, 328 (typelib_InterfaceTypeDescription *)pTD ); 329 330 if (pInterface) 331 { 332 ::uno_any_construct( 333 reinterpret_cast< uno_Any * >( pCallStack[1] ), 334 &pInterface, pTD, cpp_acquire ); 335 pInterface->release(); 336 TYPELIB_DANGER_RELEASE( pTD ); 337 *static_cast< void ** >(pReturnValue) = pCallStack[1]; 338 break; 339 } 340 TYPELIB_DANGER_RELEASE( pTD ); 341 } 342 } // else perform queryInterface() 343 default: 344 cpp2uno_call( 345 pCppI, aMemberDescr.get(), 346 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef, 347 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams, 348 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams, 349 pCallStack, pReturnValue ); 350 } 351 break; 352 } 353 default: 354 { 355 throw RuntimeException( 356 rtl::OUString::createFromAscii("no member description found!"), 357 (XInterface *)pThis ); 358 } 359 } 360 } 361 362 //================================================================================================== 363 extern "C" void privateSnippetExecutorGeneral(); 364 extern "C" void privateSnippetExecutorVoid(); 365 extern "C" void privateSnippetExecutorHyper(); 366 extern "C" void privateSnippetExecutorFloat(); 367 extern "C" void privateSnippetExecutorDouble(); 368 extern "C" void privateSnippetExecutorClass(); 369 extern "C" typedef void (*PrivateSnippetExecutor)(); 370 371 int const codeSnippetSize = 16; 372 373 unsigned char * codeSnippet( 374 unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset, 375 typelib_TypeDescriptionReference * pReturnTypeRef) 376 { 377 PrivateSnippetExecutor exec; 378 if (pReturnTypeRef == 0) { 379 exec = privateSnippetExecutorVoid; 380 } 381 else { 382 switch (pReturnTypeRef->eTypeClass) { 383 case typelib_TypeClass_VOID: 384 exec = privateSnippetExecutorVoid; 385 break; 386 case typelib_TypeClass_HYPER: 387 case typelib_TypeClass_UNSIGNED_HYPER: 388 exec = privateSnippetExecutorHyper; 389 break; 390 case typelib_TypeClass_FLOAT: 391 exec = privateSnippetExecutorFloat; 392 break; 393 case typelib_TypeClass_DOUBLE: 394 exec = privateSnippetExecutorDouble; 395 break; 396 case typelib_TypeClass_STRUCT: 397 case typelib_TypeClass_EXCEPTION: { 398 typelib_TypeDescription * pReturnTypeDescr = 0; 399 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef ); 400 bool const bSimpleReturnStruct = 401 CPPU_CURRENT_NAMESPACE::isSimpleReturnType(pReturnTypeDescr); 402 sal_Int32 const nRetSize = pReturnTypeDescr->nSize; 403 TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); 404 if (bSimpleReturnStruct && nRetSize <= 8) { 405 exec = privateSnippetExecutorGeneral; // fills eax 406 if (nRetSize > 4) 407 exec = privateSnippetExecutorHyper; // fills eax/edx 408 break; 409 } 410 } 411 case typelib_TypeClass_STRING: 412 case typelib_TypeClass_TYPE: 413 case typelib_TypeClass_SEQUENCE: 414 case typelib_TypeClass_INTERFACE: 415 case typelib_TypeClass_ANY: 416 functionIndex |= 0x80000000; 417 exec = privateSnippetExecutorClass; 418 break; 419 default: 420 exec = privateSnippetExecutorGeneral; 421 break; 422 } 423 } 424 unsigned char * p = code; 425 OSL_ASSERT(sizeof (sal_Int32) == 4); 426 // mov function_index, %eax: 427 *p++ = 0xB8; 428 *reinterpret_cast< sal_Int32 * >(p) = functionIndex; 429 p += sizeof (sal_Int32); 430 // mov vtable_offset, %edx: 431 *p++ = 0xBA; 432 *reinterpret_cast< sal_Int32 * >(p) = vtableOffset; 433 p += sizeof (sal_Int32); 434 // jmp privateSnippetExecutor: 435 *p++ = 0xE9; 436 *reinterpret_cast< sal_Int32 * >(p) 437 = ((unsigned char *) exec) - 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 reinterpret_cast< 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( 495 code, functionOffset++, vtableOffset, 496 0 /* indicates VOID */); 497 } 498 break; 499 500 case typelib_TypeClass_INTERFACE_METHOD: 501 (s++)->fn = code; 502 code = codeSnippet( 503 code, functionOffset++, vtableOffset, 504 reinterpret_cast< 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