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