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 "com/sun/star/uno/Sequence.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 "share.hxx" 39 40 #include "boost/static_assert.hpp" 41 #include <stdio.h> 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 // xxx todo: test PolyStructy<STRUCT<long>> foo() 71 if (CPPU_CURRENT_NAMESPACE::isSimpleReturnType( 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 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 default: 119 break; 120 } 121 // no longer needed 122 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 123 } 124 else // ptr to complex value | ref 125 { 126 pCppArgs[nPos] = *(void **)pCppStack; 127 128 if (! rParam.bIn) // is pure out 129 { 130 // uno out is unconstructed mem! 131 pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ); 132 pTempIndizes[nTempIndizes] = nPos; 133 // will be released at reconversion 134 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 135 } 136 // is in/inout 137 else if (bridges::cpp_uno::shared::relatesToInterfaceType( 138 pParamTypeDescr )) 139 { 140 uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ), 141 *(void **)pCppStack, pParamTypeDescr, 142 pThis->getBridge()->getCpp2Uno() ); 143 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted 144 // will be released at reconversion 145 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 146 } 147 else // direct way 148 { 149 pUnoArgs[nPos] = *(void **)pCppStack; 150 // no longer needed 151 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 152 } 153 } 154 pCppStack += sizeof(sal_Int32); // standard parameter length 155 } 156 157 // ExceptionHolder 158 uno_Any aUnoExc; // Any will be constructed by callee 159 uno_Any * pUnoExc = &aUnoExc; 160 161 // invoke uno dispatch call 162 (*pThis->getUnoI()->pDispatcher)( 163 pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc ); 164 165 // in case an exception occured... 166 if (pUnoExc) 167 { 168 // destruct temporary in/inout params 169 for ( ; nTempIndizes--; ) 170 { 171 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 172 173 if (pParams[nIndex].bIn) // is in/inout => was constructed 174 uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], 0 ); 175 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] ); 176 } 177 if (pReturnTypeDescr) 178 TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); 179 180 CPPU_CURRENT_NAMESPACE::raiseException( 181 &aUnoExc, pThis->getBridge()->getUno2Cpp() ); 182 // has to destruct the any 183 } 184 else // else no exception occured... 185 { 186 // temporary params 187 for ( ; nTempIndizes--; ) 188 { 189 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 190 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes]; 191 192 if (pParams[nIndex].bOut) // inout/out 193 { 194 // convert and assign 195 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release ); 196 uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr, 197 pThis->getBridge()->getUno2Cpp() ); 198 } 199 // destroy temp uno param 200 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); 201 202 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 203 } 204 // return 205 if (pCppReturn) // has complex return 206 { 207 if (pUnoReturn != pCppReturn) // needs reconversion 208 { 209 uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr, 210 pThis->getBridge()->getUno2Cpp() ); 211 // destroy temp uno return 212 uno_destructData( pUnoReturn, pReturnTypeDescr, 0 ); 213 } 214 if (pReturnValue != pCppReturn) { 215 // complex return ptr is set to eax if return value 216 // is not transferred via eax[/edx]: 217 *static_cast< void ** >(pReturnValue) = pCppReturn; 218 } 219 } 220 if (pReturnTypeDescr) 221 { 222 TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); 223 } 224 } 225 } 226 227 228 //================================================================================================== 229 extern "C" void cpp_vtable_call( 230 int nFunctionIndex, int nVtableOffset, void** pCallStack, 231 void * pReturnValue ) 232 { 233 OSL_ENSURE( sizeof(sal_Int32)==sizeof(void *), "### unexpected!" ); 234 235 // pCallStack: ret adr, [ret *], this, params 236 void * pThis; 237 if( nFunctionIndex & 0x80000000 ) 238 { 239 nFunctionIndex &= 0x7fffffff; 240 pThis = pCallStack[2]; 241 } 242 else 243 { 244 pThis = pCallStack[1]; 245 } 246 pThis = static_cast< char * >(pThis) - nVtableOffset; 247 bridges::cpp_uno::shared::CppInterfaceProxy * pCppI 248 = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( 249 pThis); 250 #if OSL_DEBUG_LEVEL > 1 251 fprintf( stderr, "%p %p %p pThis=%p, pCppI=%p, function index=%d, vtable offset=%d\n", pCallStack[0], pCallStack[1], pCallStack[2], pThis, pCppI, nFunctionIndex, nVtableOffset ); 252 #endif 253 typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr(); 254 #if OSL_DEBUG_LEVEL > 1 255 fprintf( stderr, "name=%s\n", rtl::OUStringToOString(pTypeDescr->aBase.pTypeName, RTL_TEXTENCODING_UTF8).getStr() ); 256 #endif 257 OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!" ); 258 if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex) 259 { 260 throw RuntimeException( 261 rtl::OUString::createFromAscii("illegal vtable index!"), 262 (XInterface *)pThis ); 263 } 264 265 // determine called method 266 sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex]; 267 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!" ); 268 269 TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] ); 270 #if OSL_DEBUG_LEVEL > 1 271 fprintf(stderr, "calling %s\n", rtl::OUStringToOString(aMemberDescr.get()->pTypeName, RTL_TEXTENCODING_UTF8).getStr()); 272 #endif 273 switch (aMemberDescr.get()->eTypeClass) 274 { 275 case typelib_TypeClass_INTERFACE_ATTRIBUTE: 276 { 277 if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex) 278 { 279 // is GET method 280 cpp2uno_call( 281 pCppI, aMemberDescr.get(), 282 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef, 283 0, 0, // no params 284 pCallStack, pReturnValue ); 285 } 286 else 287 { 288 // is SET method 289 typelib_MethodParameter aParam; 290 aParam.pTypeRef = 291 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef; 292 aParam.bIn = sal_True; 293 aParam.bOut = sal_False; 294 295 cpp2uno_call( 296 pCppI, aMemberDescr.get(), 297 0, // indicates void return 298 1, &aParam, 299 pCallStack, pReturnValue ); 300 } 301 break; 302 } 303 case typelib_TypeClass_INTERFACE_METHOD: 304 { 305 // is METHOD 306 switch (nFunctionIndex) 307 { 308 case 1: // acquire() 309 pCppI->acquireProxy(); // non virtual call! 310 break; 311 case 2: // release() 312 pCppI->releaseProxy(); // non virtual call! 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[1] ), 330 &pInterface, pTD, cpp_acquire ); 331 pInterface->release(); 332 TYPELIB_DANGER_RELEASE( pTD ); 333 *static_cast< void ** >(pReturnValue) = pCallStack[1]; 334 break; 335 } 336 TYPELIB_DANGER_RELEASE( pTD ); 337 } 338 } // else perform queryInterface() 339 default: 340 cpp2uno_call( 341 pCppI, aMemberDescr.get(), 342 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef, 343 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams, 344 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams, 345 pCallStack, pReturnValue ); 346 } 347 break; 348 } 349 default: 350 { 351 throw RuntimeException( 352 rtl::OUString::createFromAscii("no member description found!"), 353 (XInterface *)pThis ); 354 } 355 } 356 } 357 358 //================================================================================================== 359 extern "C" void privateSnippetExecutorGeneral(); 360 extern "C" void privateSnippetExecutorVoid(); 361 extern "C" void privateSnippetExecutorHyper(); 362 extern "C" void privateSnippetExecutorFloat(); 363 extern "C" void privateSnippetExecutorDouble(); 364 extern "C" void privateSnippetExecutorClass(); 365 extern "C" typedef void (*PrivateSnippetExecutor)(); 366 367 int const codeSnippetSize = 16; 368 369 unsigned char * codeSnippet( 370 unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset, 371 typelib_TypeDescriptionReference * pReturnTypeRef) 372 { 373 PrivateSnippetExecutor exec; 374 if (pReturnTypeRef == 0) { 375 exec = privateSnippetExecutorVoid; 376 } 377 else { 378 switch (pReturnTypeRef->eTypeClass) { 379 case typelib_TypeClass_VOID: 380 exec = privateSnippetExecutorVoid; 381 break; 382 case typelib_TypeClass_HYPER: 383 case typelib_TypeClass_UNSIGNED_HYPER: 384 exec = privateSnippetExecutorHyper; 385 break; 386 case typelib_TypeClass_FLOAT: 387 exec = privateSnippetExecutorFloat; 388 break; 389 case typelib_TypeClass_DOUBLE: 390 exec = privateSnippetExecutorDouble; 391 break; 392 case typelib_TypeClass_STRUCT: 393 case typelib_TypeClass_EXCEPTION: { 394 typelib_TypeDescription * pReturnTypeDescr = 0; 395 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef ); 396 bool const bSimpleReturnStruct = 397 CPPU_CURRENT_NAMESPACE::isSimpleReturnType(pReturnTypeDescr); 398 sal_Int32 const nRetSize = pReturnTypeDescr->nSize; 399 TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); 400 if (bSimpleReturnStruct && nRetSize <= 8) { 401 exec = privateSnippetExecutorGeneral; // fills eax 402 if (nRetSize > 4) 403 exec = privateSnippetExecutorHyper; // fills eax/edx 404 break; 405 } 406 } 407 case typelib_TypeClass_STRING: 408 case typelib_TypeClass_TYPE: 409 case typelib_TypeClass_SEQUENCE: 410 case typelib_TypeClass_INTERFACE: 411 case typelib_TypeClass_ANY: 412 functionIndex |= 0x80000000; 413 exec = privateSnippetExecutorClass; 414 break; 415 default: 416 exec = privateSnippetExecutorGeneral; 417 break; 418 } 419 } 420 unsigned char * p = code; 421 OSL_ASSERT(sizeof (sal_Int32) == 4); 422 // mov function_index, %eax: 423 *p++ = 0xB8; 424 *reinterpret_cast< sal_Int32 * >(p) = functionIndex; 425 p += sizeof (sal_Int32); 426 // mov vtable_offset, %edx: 427 *p++ = 0xBA; 428 *reinterpret_cast< sal_Int32 * >(p) = vtableOffset; 429 p += sizeof (sal_Int32); 430 // jmp privateSnippetExecutor: 431 *p++ = 0xE9; 432 *reinterpret_cast< sal_Int32 * >(p) 433 = ((unsigned char *) exec) - p - sizeof (sal_Int32); 434 p += sizeof (sal_Int32); 435 OSL_ASSERT(p - code <= codeSnippetSize); 436 return code + codeSnippetSize; 437 } 438 439 } 440 441 struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; 442 443 bridges::cpp_uno::shared::VtableFactory::Slot * 444 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) 445 { 446 return static_cast< Slot * >(block) + 2; 447 } 448 449 sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize( 450 sal_Int32 slotCount) 451 { 452 return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize; 453 } 454 455 bridges::cpp_uno::shared::VtableFactory::Slot * 456 bridges::cpp_uno::shared::VtableFactory::initializeBlock( 457 void * block, sal_Int32 slotCount) 458 { 459 Slot * slots = mapBlockToVtable(block); 460 slots[-2].fn = 0; 461 slots[-1].fn = 0; 462 return slots + slotCount; 463 } 464 465 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions( 466 Slot ** slots, unsigned char * code, 467 typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset, 468 sal_Int32 functionCount, sal_Int32 vtableOffset) 469 { 470 (*slots) -= functionCount; 471 Slot * s = *slots; 472 for (sal_Int32 i = 0; i < type->nMembers; ++i) { 473 typelib_TypeDescription * member = 0; 474 TYPELIB_DANGER_GET(&member, type->ppMembers[i]); 475 OSL_ASSERT(member != 0); 476 switch (member->eTypeClass) { 477 case typelib_TypeClass_INTERFACE_ATTRIBUTE: 478 // Getter: 479 (s++)->fn = code; 480 code = codeSnippet( 481 code, functionOffset++, vtableOffset, 482 reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >( 483 member)->pAttributeTypeRef); 484 // Setter: 485 if (!reinterpret_cast< 486 typelib_InterfaceAttributeTypeDescription * >( 487 member)->bReadOnly) 488 { 489 (s++)->fn = code; 490 code = codeSnippet( 491 code, functionOffset++, vtableOffset, 492 0 /* indicates VOID */); 493 } 494 break; 495 496 case typelib_TypeClass_INTERFACE_METHOD: 497 (s++)->fn = code; 498 code = codeSnippet( 499 code, functionOffset++, vtableOffset, 500 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >( 501 member)->pReturnTypeRef); 502 break; 503 504 default: 505 OSL_ASSERT(false); 506 break; 507 } 508 TYPELIB_DANGER_RELEASE(member); 509 } 510 return code; 511 } 512 513 void bridges::cpp_uno::shared::VtableFactory::flushCode( 514 unsigned char const *, unsigned char const *) 515 {} 516