1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_bridges.hxx" 30 31 #include <sal/alloca.h> 32 33 #include <com/sun/star/uno/genfunc.hxx> 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 "cc50_solaris_intel.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 sal_Int64 * pRegisterReturn /* space for register return */ ) 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 = pRegisterReturn; // 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 ] = pUnoArgs[ nPos ] = pCppStack; 111 switch (pParamTypeDescr->eTypeClass) 112 { 113 case typelib_TypeClass_HYPER: 114 case typelib_TypeClass_UNSIGNED_HYPER: 115 case typelib_TypeClass_DOUBLE: 116 pCppStack += sizeof(sal_Int32); // extra long 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 no exception occured... 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::cc50_solaris_intel_raiseException( 178 &aUnoExc, pThis->getBridge()->getUno2Cpp() ); 179 // has to destruct the any 180 } 181 else // else no exception occured... 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( 193 pCppArgs[nIndex], pParamTypeDescr, 194 reinterpret_cast< uno_ReleaseFunc >(cpp_release) ); 195 uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr, 196 pThis->getBridge()->getUno2Cpp() ); 197 } 198 // destroy temp uno param 199 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); 200 201 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 202 } 203 // return 204 if (pCppReturn) // has complex return 205 { 206 if (pUnoReturn != pCppReturn) // needs reconversion 207 { 208 uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr, 209 pThis->getBridge()->getUno2Cpp() ); 210 // destroy temp uno return 211 uno_destructData( pUnoReturn, pReturnTypeDescr, 0 ); 212 } 213 // complex return ptr is set to eax 214 *(void **)pRegisterReturn = pCppReturn; 215 } 216 if (pReturnTypeDescr) 217 { 218 TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); 219 } 220 } 221 } 222 223 224 //================================================================================================== 225 extern "C" void cpp_vtable_call( 226 int nFunctionIndex, int nVtableOffset, void** pCallStack, 227 sal_Int64 nRegReturn ) 228 { 229 OSL_ENSURE( sizeof(sal_Int32)==sizeof(void *), "### unexpected!" ); 230 231 // pCallStack: ret adr, [ret *], this, params 232 void * pThis; 233 if( nFunctionIndex & 0x80000000 ) 234 { 235 nFunctionIndex &= 0x7fffffff; 236 pThis = pCallStack[2]; 237 } 238 else 239 { 240 pThis = pCallStack[1]; 241 } 242 pThis = static_cast< char * >(pThis) - nVtableOffset; 243 bridges::cpp_uno::shared::CppInterfaceProxy * pCppI 244 = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( 245 pThis); 246 247 typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr(); 248 249 OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex, 250 "### illegal vtable index!" ); 251 if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex) 252 { 253 throw RuntimeException( rtl::OUString::createFromAscii("illegal vtable index!"), (XInterface *)pThis ); 254 } 255 256 // determine called method 257 sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex]; 258 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!" ); 259 260 TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] ); 261 262 switch (aMemberDescr.get()->eTypeClass) 263 { 264 case typelib_TypeClass_INTERFACE_ATTRIBUTE: 265 { 266 if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex) 267 { 268 // is GET method 269 cpp2uno_call( 270 pCppI, aMemberDescr.get(), 271 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef, 272 0, 0, // no params 273 pCallStack, &nRegReturn ); 274 } 275 else 276 { 277 // is SET method 278 typelib_MethodParameter aParam; 279 aParam.pTypeRef = 280 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef; 281 aParam.bIn = sal_True; 282 aParam.bOut = sal_False; 283 284 cpp2uno_call( 285 pCppI, aMemberDescr.get(), 286 0, // indicates void return 287 1, &aParam, 288 pCallStack, &nRegReturn ); 289 } 290 break; 291 } 292 case typelib_TypeClass_INTERFACE_METHOD: 293 { 294 // is METHOD 295 switch (nFunctionIndex) 296 { 297 // standard XInterface vtable calls 298 case 1: // acquire() 299 pCppI->acquireProxy(); // non virtual call! 300 break; 301 case 2: // release() 302 pCppI->releaseProxy(); // non virtual call! 303 break; 304 case 0: // queryInterface() opt 305 { 306 typelib_TypeDescription * pTD = 0; 307 TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pCallStack[3] )->getTypeLibType() ); 308 if (pTD) 309 { 310 XInterface * pInterface = 0; 311 (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)( 312 pCppI->getBridge()->getCppEnv(), 313 (void **)&pInterface, pCppI->getOid().pData, 314 (typelib_InterfaceTypeDescription *)pTD ); 315 316 if (pInterface) 317 { 318 ::uno_any_construct( 319 reinterpret_cast< uno_Any * >( pCallStack[1] ), 320 &pInterface, pTD, 321 reinterpret_cast< uno_AcquireFunc >(cpp_acquire) ); 322 pInterface->release(); 323 TYPELIB_DANGER_RELEASE( pTD ); 324 *(void **)&nRegReturn = pCallStack[1]; 325 break; 326 } 327 TYPELIB_DANGER_RELEASE( pTD ); 328 } 329 } // else perform queryInterface() 330 default: 331 cpp2uno_call( 332 pCppI, aMemberDescr.get(), 333 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef, 334 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams, 335 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams, 336 pCallStack, &nRegReturn ); 337 } 338 break; 339 } 340 default: 341 { 342 throw RuntimeException( rtl::OUString::createFromAscii("no member description found!"), (XInterface *)pThis ); 343 } 344 } 345 } 346 347 //================================================================================================== 348 bool isSimpleStruct(typelib_TypeDescriptionReference * type) { 349 typelib_TypeDescription * td = 0; 350 TYPELIB_DANGER_GET(&td, type); 351 OSL_ASSERT(td != 0); 352 for (typelib_CompoundTypeDescription * ctd 353 = reinterpret_cast< typelib_CompoundTypeDescription * >(td); 354 ctd != 0; ctd = ctd->pBaseTypeDescription) 355 { 356 OSL_ASSERT(ctd->aBase.eTypeClass == typelib_TypeClass_STRUCT); 357 for (sal_Int32 i = 0; i < ctd->nMembers; ++i) { 358 typelib_TypeClass c = ctd->ppTypeRefs[i]->eTypeClass; 359 switch (c) { 360 case typelib_TypeClass_STRING: 361 case typelib_TypeClass_TYPE: 362 case typelib_TypeClass_ANY: 363 case typelib_TypeClass_SEQUENCE: 364 case typelib_TypeClass_INTERFACE: 365 return false; 366 case typelib_TypeClass_STRUCT: 367 if (!isSimpleStruct(ctd->ppTypeRefs[i])) { 368 return false; 369 } 370 break; 371 default: 372 OSL_ASSERT( 373 c <= typelib_TypeClass_DOUBLE 374 || c == typelib_TypeClass_ENUM); 375 break; 376 } 377 } 378 } 379 TYPELIB_DANGER_RELEASE(td); 380 return true; 381 } 382 383 extern "C" void privateSnippetExecutorGeneral(); 384 extern "C" void privateSnippetExecutorVoid(); 385 extern "C" void privateSnippetExecutorHyper(); 386 extern "C" void privateSnippetExecutorFloat(); 387 extern "C" void privateSnippetExecutorDouble(); 388 extern "C" void privateSnippetExecutorStruct(); 389 extern "C" typedef void (*PrivateSnippetExecutor)(); 390 391 int const codeSnippetSize = 16; 392 393 unsigned char * codeSnippet( 394 unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset, 395 typelib_TypeDescriptionReference * returnType) 396 { 397 typelib_TypeClass c = returnType == 0 398 ? typelib_TypeClass_VOID : returnType->eTypeClass; 399 if (returnType != 0 && !bridges::cpp_uno::shared::isSimpleType(c)) { 400 functionIndex |= 0x80000000; 401 } 402 PrivateSnippetExecutor exec; 403 switch (c) { 404 case typelib_TypeClass_VOID: 405 exec = privateSnippetExecutorVoid; 406 break; 407 case typelib_TypeClass_HYPER: 408 case typelib_TypeClass_UNSIGNED_HYPER: 409 exec = privateSnippetExecutorHyper; 410 break; 411 case typelib_TypeClass_FLOAT: 412 exec = privateSnippetExecutorFloat; 413 break; 414 case typelib_TypeClass_DOUBLE: 415 exec = privateSnippetExecutorDouble; 416 break; 417 case typelib_TypeClass_STRUCT: 418 OSL_ASSERT(returnType != 0); 419 // For "simple" (more-or-less POD, but not exactly) structs, the caller 420 // pops the pointer to the return value off the stack, as documented in 421 // the Intel SYSV ABI; for other structs (which includes STRING, TYPE, 422 // ANY, sequences, and interfaces, btw.), the callee pops the pointer to 423 // the return value off the stack: 424 exec = isSimpleStruct(returnType) 425 ? privateSnippetExecutorStruct : privateSnippetExecutorGeneral; 426 break; 427 default: 428 exec = privateSnippetExecutorGeneral; 429 break; 430 } 431 unsigned char * p = code; 432 OSL_ASSERT(sizeof (sal_Int32) == 4); 433 // mov function_index, %eax: 434 *p++ = 0xB8; 435 *reinterpret_cast< sal_Int32 * >(p) = functionIndex; 436 p += sizeof (sal_Int32); 437 // mov vtable_offset, %edx: 438 *p++ = 0xBA; 439 *reinterpret_cast< sal_Int32 * >(p) = vtableOffset; 440 p += sizeof (sal_Int32); 441 // jmp privateSnippetExecutor: 442 *p++ = 0xE9; 443 #pragma disable_warn 444 void * e = reinterpret_cast< void * >(exec); 445 #pragma enable_warn 446 *reinterpret_cast< sal_Int32 * >(p) 447 = static_cast< unsigned char * >(e) - p - sizeof (sal_Int32); 448 p += sizeof (sal_Int32); 449 OSL_ASSERT(p - code <= codeSnippetSize); 450 return code + codeSnippetSize; 451 } 452 453 } 454 455 struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; 456 457 bridges::cpp_uno::shared::VtableFactory::Slot * 458 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) { 459 return static_cast< Slot * >(block) + 1; 460 } 461 462 sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize( 463 sal_Int32 slotCount) 464 { 465 return (slotCount + 3) * sizeof (Slot) + slotCount * codeSnippetSize; 466 } 467 468 bridges::cpp_uno::shared::VtableFactory::Slot * 469 bridges::cpp_uno::shared::VtableFactory::initializeBlock( 470 void * block, sal_Int32 slotCount) 471 { 472 Slot * slots = mapBlockToVtable(block) + 2; 473 slots[-3].fn = 0; // RTTI 474 slots[-2].fn = 0; // null 475 slots[-1].fn = 0; // destructor 476 return slots + slotCount; 477 } 478 479 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions( 480 Slot ** slots, unsigned char * code, 481 typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset, 482 sal_Int32 functionCount, sal_Int32 vtableOffset) 483 { 484 (*slots) -= functionCount; 485 Slot * s = *slots; 486 for (sal_Int32 i = 0; i < type->nMembers; ++i) { 487 typelib_TypeDescription * member = 0; 488 TYPELIB_DANGER_GET(&member, type->ppMembers[i]); 489 OSL_ASSERT(member != 0); 490 switch (member->eTypeClass) { 491 case typelib_TypeClass_INTERFACE_ATTRIBUTE: 492 // Getter: 493 (s++)->fn = code; 494 code = codeSnippet( 495 code, functionOffset++, vtableOffset, 496 reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >( 497 member)->pAttributeTypeRef); 498 // Setter: 499 if (!reinterpret_cast< 500 typelib_InterfaceAttributeTypeDescription * >( 501 member)->bReadOnly) 502 { 503 (s++)->fn = code; 504 code = codeSnippet(code, functionOffset++, vtableOffset, 0); 505 } 506 break; 507 508 case typelib_TypeClass_INTERFACE_METHOD: 509 (s++)->fn = code; 510 code = codeSnippet( 511 code, functionOffset++, vtableOffset, 512 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >( 513 member)->pReturnTypeRef); 514 break; 515 516 default: 517 OSL_ASSERT(false); 518 break; 519 } 520 TYPELIB_DANGER_RELEASE(member); 521 } 522 return code; 523 } 524 525 void bridges::cpp_uno::shared::VtableFactory::flushCode( 526 unsigned char const *, unsigned char const *) 527 {} 528