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