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