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