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