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