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 <malloc.h> 32 33 #include <com/sun/star/uno/genfunc.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 "msci.hxx" 43 44 using namespace ::com::sun::star::uno; 45 46 namespace 47 { 48 49 //================================================================================================== 50 static inline typelib_TypeClass cpp2uno_call( 51 bridges::cpp_uno::shared::CppInterfaceProxy * pThis, 52 const typelib_TypeDescription * pMemberTypeDescr, 53 typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return 54 sal_Int32 nParams, typelib_MethodParameter * pParams, 55 void ** pCallStack, 56 sal_Int64 * pRegisterReturn /* space for register return */ ) 57 { 58 // pCallStack: ret, this, [complex return ptr], params 59 char * pCppStack = (char *)(pCallStack +2); 60 61 // return 62 typelib_TypeDescription * pReturnTypeDescr = 0; 63 if (pReturnTypeRef) 64 { 65 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef ); 66 } 67 68 void * pUnoReturn = 0; 69 void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need 70 71 if (pReturnTypeDescr) 72 { 73 if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr )) 74 { 75 pUnoReturn = pRegisterReturn; // direct way for simple types 76 } 77 else // complex return via ptr (pCppReturn) 78 { 79 pCppReturn = *(void **)pCppStack; 80 pCppStack += sizeof(void *); 81 82 pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( 83 pReturnTypeDescr ) 84 ? alloca( pReturnTypeDescr->nSize ) 85 : pCppReturn); // direct way 86 } 87 } 88 89 // stack space 90 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" ); 91 // parameters 92 void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams ); 93 void ** pCppArgs = pUnoArgs + nParams; 94 // indizes of values this have to be converted (interface conversion cpp<=>uno) 95 sal_Int32 * pTempIndizes = (sal_Int32 *)(pUnoArgs + (2 * nParams)); 96 // type descriptions for reconversions 97 typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams)); 98 99 sal_Int32 nTempIndizes = 0; 100 101 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) 102 { 103 const typelib_MethodParameter & rParam = pParams[nPos]; 104 typelib_TypeDescription * pParamTypeDescr = 0; 105 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef ); 106 107 if (!rParam.bOut 108 && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr )) 109 // value 110 { 111 pCppArgs[nPos] = pCppStack; 112 pUnoArgs[nPos] = pCppStack; 113 switch (pParamTypeDescr->eTypeClass) 114 { 115 case typelib_TypeClass_HYPER: 116 case typelib_TypeClass_UNSIGNED_HYPER: 117 case typelib_TypeClass_DOUBLE: 118 pCppStack += sizeof(sal_Int32); // extra long 119 break; 120 default: 121 break; 122 } 123 // no longer needed 124 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 125 } 126 else // ptr to complex value | ref 127 { 128 pCppArgs[nPos] = *(void **)pCppStack; 129 130 if (! rParam.bIn) // is pure out 131 { 132 // uno out is unconstructed mem! 133 pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ); 134 pTempIndizes[nTempIndizes] = nPos; 135 // will be released at reconversion 136 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 137 } 138 // is in/inout 139 else if (bridges::cpp_uno::shared::relatesToInterfaceType( 140 pParamTypeDescr )) 141 { 142 ::uno_copyAndConvertData( 143 pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ), 144 *(void **)pCppStack, pParamTypeDescr, 145 pThis->getBridge()->getCpp2Uno() ); 146 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted 147 // will be released at reconversion 148 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 149 } 150 else // direct way 151 { 152 pUnoArgs[nPos] = *(void **)pCppStack; 153 // no longer needed 154 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 155 } 156 } 157 pCppStack += sizeof(sal_Int32); // standard parameter length 158 } 159 160 // ExceptionHolder 161 uno_Any aUnoExc; // Any will be constructed by callee 162 uno_Any * pUnoExc = &aUnoExc; 163 164 // invoke uno dispatch call 165 (*pThis->getUnoI()->pDispatcher)( 166 pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc ); 167 168 // in case an exception occured... 169 if (pUnoExc) 170 { 171 // destruct temporary in/inout params 172 while (nTempIndizes--) 173 { 174 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 175 176 if (pParams[nIndex].bIn) // is in/inout => was constructed 177 { 178 ::uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], 0 ); 179 } 180 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] ); 181 } 182 if (pReturnTypeDescr) 183 { 184 TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); 185 } 186 187 CPPU_CURRENT_NAMESPACE::msci_raiseException( 188 &aUnoExc, pThis->getBridge()->getUno2Cpp() ); 189 // has to destruct the any 190 // is here for dummy 191 return typelib_TypeClass_VOID; 192 } 193 else // else no exception occured... 194 { 195 // temporary params 196 while (nTempIndizes--) 197 { 198 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 199 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes]; 200 201 if (pParams[nIndex].bOut) // inout/out 202 { 203 // convert and assign 204 ::uno_destructData( 205 pCppArgs[nIndex], pParamTypeDescr, cpp_release ); 206 ::uno_copyAndConvertData( 207 pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr, 208 pThis->getBridge()->getUno2Cpp() ); 209 } 210 // destroy temp uno param 211 ::uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); 212 213 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 214 } 215 // return 216 if (pCppReturn) // has complex return 217 { 218 if (pUnoReturn != pCppReturn) // needs reconversion 219 { 220 ::uno_copyAndConvertData( 221 pCppReturn, pUnoReturn, pReturnTypeDescr, 222 pThis->getBridge()->getUno2Cpp() ); 223 // destroy temp uno return 224 ::uno_destructData( 225 pUnoReturn, pReturnTypeDescr, 0 ); 226 } 227 // complex return ptr is set to eax 228 *(void **)pRegisterReturn = pCppReturn; 229 } 230 if (pReturnTypeDescr) 231 { 232 typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass; 233 TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); 234 return eRet; 235 } 236 else 237 return typelib_TypeClass_VOID; 238 } 239 } 240 241 //================================================================================================== 242 static typelib_TypeClass __cdecl cpp_mediate( 243 void ** pCallStack, sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset, 244 sal_Int64 * pRegisterReturn /* space for register return */ ) 245 { 246 OSL_ENSURE( sizeof(sal_Int32)==sizeof(void *), "### unexpected!" ); 247 248 // pCallStack: ret adr, this, [ret *], params 249 void * pThis = static_cast< char * >(pCallStack[1]) - 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 OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex, 256 "### illegal vtable index!" ); 257 if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex) 258 { 259 throw RuntimeException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("illegal vtable index!") ), 260 (XInterface *)pThis ); 261 } 262 263 // determine called method 264 sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex]; 265 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!" ); 266 267 TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] ); 268 269 typelib_TypeClass eRet; 270 switch (aMemberDescr.get()->eTypeClass) 271 { 272 case typelib_TypeClass_INTERFACE_ATTRIBUTE: 273 { 274 if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex) 275 { 276 // is GET method 277 eRet = cpp2uno_call( 278 pCppI, aMemberDescr.get(), 279 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef, 280 0, 0, // no params 281 pCallStack, pRegisterReturn ); 282 } 283 else 284 { 285 // is SET method 286 typelib_MethodParameter aParam; 287 aParam.pTypeRef = 288 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef; 289 aParam.bIn = sal_True; 290 aParam.bOut = sal_False; 291 292 eRet = cpp2uno_call( 293 pCppI, aMemberDescr.get(), 294 0, // indicates void return 295 1, &aParam, 296 pCallStack, pRegisterReturn ); 297 } 298 break; 299 } 300 case typelib_TypeClass_INTERFACE_METHOD: 301 { 302 // is METHOD 303 switch (nFunctionIndex) 304 { 305 // standard XInterface vtable calls 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[2] ), 330 &pInterface, pTD, cpp_acquire ); 331 pInterface->release(); 332 TYPELIB_DANGER_RELEASE( pTD ); 333 *(void **)pRegisterReturn = pCallStack[2]; 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( RTL_CONSTASCII_USTRINGPARAM("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 __declspec(naked) void __cdecl cpp_vtable_call(void) 369 { 370 __asm 371 { 372 sub esp, 8 // space for immediate return type 373 push esp 374 push edx // vtable offset 375 push eax // function index 376 mov eax, esp 377 add eax, 20 378 push eax // original stack ptr 379 380 call cpp_mediate 381 add esp, 16 382 383 cmp eax, typelib_TypeClass_FLOAT 384 je Lfloat 385 cmp eax, typelib_TypeClass_DOUBLE 386 je Ldouble 387 cmp eax, typelib_TypeClass_HYPER 388 je Lhyper 389 cmp eax, typelib_TypeClass_UNSIGNED_HYPER 390 je Lhyper 391 // rest is eax 392 pop eax 393 add esp, 4 394 ret 395 Lhyper: 396 pop eax 397 pop edx 398 ret 399 Lfloat: 400 fld dword ptr [esp] 401 add esp, 8 402 ret 403 Ldouble: 404 fld qword ptr [esp] 405 add esp, 8 406 ret 407 } 408 } 409 410 //================================================================================================== 411 int const codeSnippetSize = 16; 412 413 unsigned char * codeSnippet( 414 unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset) 415 { 416 unsigned char * p = code; 417 OSL_ASSERT(sizeof (sal_Int32) == 4); 418 // mov eax, functionIndex: 419 *p++ = 0xB8; 420 *reinterpret_cast< sal_Int32 * >(p) = functionIndex; 421 p += sizeof (sal_Int32); 422 // mov edx, vtableOffset: 423 *p++ = 0xBA; 424 *reinterpret_cast< sal_Int32 * >(p) = vtableOffset; 425 p += sizeof (sal_Int32); 426 // jmp rel32 cpp_vtable_call: 427 *p++ = 0xE9; 428 *reinterpret_cast< sal_Int32 * >(p) 429 = ((unsigned char *) cpp_vtable_call) - p - sizeof (sal_Int32); 430 p += sizeof (sal_Int32); 431 OSL_ASSERT(p - code <= codeSnippetSize); 432 return code + codeSnippetSize; 433 } 434 435 } 436 437 struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; 438 439 bridges::cpp_uno::shared::VtableFactory::Slot * 440 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) 441 { 442 return static_cast< Slot * >(block) + 1; 443 } 444 445 sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize( 446 sal_Int32 slotCount) 447 { 448 return (slotCount + 1) * sizeof (Slot) + slotCount * codeSnippetSize; 449 } 450 451 bridges::cpp_uno::shared::VtableFactory::Slot * 452 bridges::cpp_uno::shared::VtableFactory::initializeBlock( 453 void * block, sal_Int32 slotCount) 454 { 455 struct Rtti { 456 sal_Int32 n0, n1, n2; 457 type_info * rtti; 458 Rtti(): 459 n0(0), n1(0), n2(0), 460 rtti(CPPU_CURRENT_NAMESPACE::msci_getRTTI( 461 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 462 "com.sun.star.uno.XInterface")))) 463 {} 464 }; 465 static Rtti rtti; 466 467 Slot * slots = mapBlockToVtable(block); 468 slots[-1].fn = &rtti; 469 return slots + slotCount; 470 } 471 472 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions( 473 Slot ** slots, unsigned char * code, 474 typelib_InterfaceTypeDescription const *, sal_Int32 functionOffset, 475 sal_Int32 functionCount, sal_Int32 vtableOffset) 476 { 477 (*slots) -= functionCount; 478 Slot * s = *slots; 479 for (sal_Int32 i = 0; i < functionCount; ++i) { 480 (s++)->fn = code; 481 code = codeSnippet(code, functionOffset++, vtableOffset); 482 } 483 return code; 484 } 485 486 void bridges::cpp_uno::shared::VtableFactory::flushCode( 487 unsigned char const *, unsigned char const *) 488 {} 489