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