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