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 <malloc.h> 32 33 #include <com/sun/star/uno/genfunc.hxx> 34 #include <uno/data.h> 35 36 #include "bridges/cpp_uno/shared/bridge.hxx" 37 #include "bridges/cpp_uno/shared/types.hxx" 38 #include "bridges/cpp_uno/shared/unointerfaceproxy.hxx" 39 #include "bridges/cpp_uno/shared/vtables.hxx" 40 41 #include "share.hxx" 42 43 #include <stdio.h> 44 #include <string.h> 45 46 47 using namespace ::rtl; 48 using namespace ::com::sun::star::uno; 49 50 namespace 51 { 52 static sal_Int32 53 invoke_count_words(char * pPT) 54 { 55 sal_Int32 overflow = 0, gpr = 0, fpr = 0; 56 int c; // character of parameter type being decoded 57 58 while (*pPT != 'X') { 59 c = *pPT; 60 switch (c) { 61 case 'D': /* type is double */ 62 if (fpr < 2) fpr++; else overflow+=2; 63 break; 64 65 case 'F': /* type is float */ 66 if (fpr < 2) fpr++; else overflow++; 67 break; 68 69 case 'H': /* type is long long */ 70 if (gpr < 4) gpr+=2; else gpr=5, overflow+=2; 71 break; 72 73 case 'S': 74 case 'T': 75 case 'B': 76 case 'C': 77 if (gpr < 5) gpr++; else overflow++; 78 break; 79 80 default: 81 if (gpr < 5) gpr++; else overflow++; 82 break; 83 } 84 pPT++; 85 } 86 /* Round up number of overflow words to ensure stack 87 stays aligned to 8 bytes. */ 88 return (overflow + 1) & ~1; 89 } 90 91 static void 92 //invoke_copy_to_stack(sal_Int32 paramCount, sal_Int32 * pStackLongs, char * pPT, sal_Int32* d_ov, sal_Int32 overflow) 93 invoke_copy_to_stack(sal_Int32 * pStackLongs, char * pPT, sal_Int32* d_ov, sal_Int32 overflow) 94 { 95 sal_Int32 *d_gpr = d_ov + overflow; 96 sal_Int64 *d_fpr = (sal_Int64 *)(d_gpr + 5); 97 sal_Int32 gpr = 0, fpr = 0; 98 char c; 99 100 while (*pPT != 'X') { 101 c = *pPT; 102 switch (c) { 103 case 'D': /* type is double */ 104 if (fpr < 2) 105 *((double*) d_fpr) = *((double *)pStackLongs), d_fpr++, fpr++; 106 else 107 *((double*) d_ov ) = *((double *)pStackLongs), d_ov+=2; 108 109 pStackLongs += 2; 110 break; 111 112 case 'F': /* type is float */ 113 if (fpr < 2) { 114 *((sal_Int64*) d_fpr) = 0; 115 *((float*) d_fpr) = *((float *)pStackLongs), d_fpr++, fpr++; 116 } 117 else { 118 *((sal_Int64*) d_ov) = 0; 119 *((float*) d_ov ) = *((float *)pStackLongs), d_ov++; 120 } 121 122 pStackLongs += 1; 123 break; 124 125 case 'H': /* type is long long */ 126 if (gpr < 4) { 127 *((sal_Int64*) d_gpr) = *((sal_Int64*) pStackLongs), d_gpr+=2, gpr+=2; 128 } 129 else { 130 *((sal_Int64*) d_ov ) = *((sal_Int64*) pStackLongs), d_ov+=2, gpr=5; 131 } 132 pStackLongs += 2; 133 break; 134 135 case 'S': 136 if (gpr < 5) 137 *((sal_uInt32*)d_gpr) = *((unsigned short*)pStackLongs), d_gpr++, gpr++; 138 else 139 *((sal_uInt32*)d_ov ) = *((unsigned short*)pStackLongs), d_ov++; 140 pStackLongs += 1; 141 break; 142 143 case 'T': 144 if (gpr < 5) 145 *((sal_Int32*)d_gpr) = *((signed short*)pStackLongs), d_gpr++, gpr++; 146 else 147 *((sal_Int32*)d_ov ) = *((signed short*)pStackLongs), d_ov++; 148 pStackLongs += 1; 149 break; 150 151 case 'B': 152 if (gpr < 5) 153 *((sal_uInt32*)d_gpr) = *((unsigned char*)pStackLongs), d_gpr++, gpr++; 154 else 155 *((sal_uInt32*)d_ov ) = *((unsigned char*)pStackLongs), d_ov++; 156 pStackLongs += 1; 157 break; 158 159 case 'C': 160 if (gpr < 5) 161 *((sal_Int32*)d_gpr) = *((signed char*)pStackLongs), d_gpr++, gpr++; 162 else 163 *((sal_Int32*)d_ov ) = *((signed char*)pStackLongs), d_ov++; 164 pStackLongs += 1; 165 break; 166 167 default: 168 if (gpr < 5) 169 *((sal_Int32*)d_gpr) = *pStackLongs, d_gpr++, gpr++; 170 else 171 *((sal_Int32*)d_ov ) = *pStackLongs, d_ov++; 172 pStackLongs += 1; 173 break; 174 } 175 pPT++; 176 } 177 } 178 179 //================================================================================================== 180 static void callVirtualMethod( 181 void * pThis, 182 sal_Int32 nVtableIndex, 183 void * pRegisterReturn, 184 typelib_TypeClass eReturnType, 185 char * pPT, 186 sal_Int32 * pStackLongs, 187 sal_Int32 nStackLongs) 188 { 189 190 // parameter list is mixed list of * and values 191 // reference parameters are pointers 192 193 // the basic idea here is to use gpr[5] as a storage area for 194 // the future values of registers r2 to r6 needed for the call, 195 // and similarly fpr[2] as a storage area for the future values 196 // of floating point registers f0 to f2 197 198 sal_Int32 *vtable = *(sal_Int32 **)pThis; 199 // sal_Int32 method = vtable[nVtableIndex + 2]; 200 sal_Int32 method = vtable[nVtableIndex]; 201 sal_Int32 overflow = invoke_count_words (pPT); 202 sal_Int32 result; 203 volatile double dret; // temporary function return values 204 volatile float fret; 205 volatile int iret, iret2; 206 207 void * dummy = alloca(32); // dummy alloca to force r11 usage for exception handling 208 209 __asm__ __volatile__ 210 ( 211 "lr 7,15\n\t" 212 "ahi 7,-48\n\t" 213 214 "lr 3,%2\n\t" 215 "sll 3,2\n\t" 216 "lcr 3,3\n\t" 217 "l 2,0(15)\n\t" 218 "la 15,0(3,7)\n\t" 219 "st 2,0(15)\n\t" 220 221 "lr 2,%0\n\t" 222 "lr 3,%1\n\t" 223 "la 4,96(15)\n\t" 224 "lr 5,%2\n\t" 225 "basr 14,%3\n\t" 226 227 "ld 0,116(7)\n\t" 228 "ld 2,124(7)\n\t" 229 "lm 2,6,96(7)\n\t" 230 : 231 : "r" (pStackLongs), 232 "r" (pPT), 233 "r" (overflow), 234 "a" (invoke_copy_to_stack), 235 "a" (method), 236 "X" (dummy) 237 : "2", "3", "4", "5", "6", "7", "memory" 238 ); 239 // "basr 14,%8\n\t" 240 241 (*(void (*)())method)(); 242 243 __asm__ __volatile__ 244 ( 245 "la 15,48(7)\n\t" 246 247 "lr %2,2\n\t" 248 "lr %3,3\n\t" 249 "ler %0,0\n\t" 250 "ldr %1,0\n\t" 251 252 : "=f" (fret), "=f" (dret), "=r" (iret), "=r" (iret2) 253 ); 254 255 switch( eReturnType ) 256 { 257 case typelib_TypeClass_HYPER: 258 case typelib_TypeClass_UNSIGNED_HYPER: 259 // ((long*)pRegisterReturn)[0] = iret; 260 ((long*)pRegisterReturn)[1] = iret2; 261 case typelib_TypeClass_LONG: 262 case typelib_TypeClass_UNSIGNED_LONG: 263 case typelib_TypeClass_ENUM: 264 ((long*)pRegisterReturn)[0] = iret; 265 break; 266 case typelib_TypeClass_CHAR: 267 case typelib_TypeClass_SHORT: 268 case typelib_TypeClass_UNSIGNED_SHORT: 269 *(unsigned short*)pRegisterReturn = (unsigned short)iret; 270 break; 271 case typelib_TypeClass_BOOLEAN: 272 case typelib_TypeClass_BYTE: 273 *(unsigned char*)pRegisterReturn = (unsigned char)iret; 274 break; 275 case typelib_TypeClass_FLOAT: 276 *(float*)pRegisterReturn = fret; 277 break; 278 case typelib_TypeClass_DOUBLE: 279 *(double*)pRegisterReturn = dret; 280 break; 281 } 282 } 283 284 285 //============================================================================ 286 static void cpp_call( 287 bridges::cpp_uno::shared::UnoInterfaceProxy * pThis, 288 bridges::cpp_uno::shared::VtableSlot aVtableSlot, 289 typelib_TypeDescriptionReference * pReturnTypeRef, 290 sal_Int32 nParams, typelib_MethodParameter * pParams, 291 void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc ) 292 { 293 // max space for: [complex ret ptr], values|ptr ... 294 char * pCppStack = 295 (char *)alloca( sizeof(sal_Int32) + ((nParams+2) * sizeof(sal_Int64)) ); 296 char * pCppStackStart = pCppStack; 297 298 // need to know parameter types for callVirtualMethod so generate a signature string 299 char * pParamType = (char *) alloca(nParams+2); 300 char * pPT = pParamType; 301 302 // return 303 typelib_TypeDescription * pReturnTypeDescr = 0; 304 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef ); 305 OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" ); 306 307 void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion 308 309 if (pReturnTypeDescr) 310 { 311 if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr )) 312 { 313 pCppReturn = pUnoReturn; // direct way for simple types 314 } 315 else 316 { 317 // complex return via ptr 318 pCppReturn = *(void **)pCppStack = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr ) 319 ? alloca( pReturnTypeDescr->nSize ) 320 : pUnoReturn); // direct way 321 *pPT++ = 'I'; //signify that a complex return type on stack 322 pCppStack += sizeof(void *); 323 } 324 } 325 // push "this" pointer 326 void * pAdjustedThisPtr = reinterpret_cast< void ** >( pThis->getCppI() ) + aVtableSlot.offset; 327 *(void**)pCppStack = pAdjustedThisPtr; 328 pCppStack += sizeof( void* ); 329 *pPT++ = 'I'; 330 331 // stack space 332 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" ); 333 // args 334 void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams ); 335 // indizes of values this have to be converted (interface conversion cpp<=>uno) 336 sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams); 337 // type descriptions for reconversions 338 typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams)); 339 340 sal_Int32 nTempIndizes = 0; 341 342 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) 343 { 344 const typelib_MethodParameter & rParam = pParams[nPos]; 345 typelib_TypeDescription * pParamTypeDescr = 0; 346 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef ); 347 348 if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr )) 349 { 350 uno_copyAndConvertData( pCppArgs[nPos] = pCppStack, pUnoArgs[nPos], pParamTypeDescr, 351 pThis->getBridge()->getUno2Cpp() ); 352 353 switch (pParamTypeDescr->eTypeClass) 354 { 355 356 // we need to know type of each param so that we know whether to use 357 // gpr or fpr to pass in parameters: 358 // Key: I - int, long, pointer, etc means pass in gpr 359 // B - byte value passed in gpr 360 // S - short value passed in gpr 361 // F - float value pass in fpr 362 // D - double value pass in fpr 363 // H - long long int pass in proper pairs of gpr (3,4) (5,6), etc 364 // X - indicates end of parameter description string 365 366 case typelib_TypeClass_LONG: 367 case typelib_TypeClass_UNSIGNED_LONG: 368 case typelib_TypeClass_ENUM: 369 *pPT++ = 'I'; 370 break; 371 case typelib_TypeClass_SHORT: 372 *pPT++ = 'T'; 373 break; 374 case typelib_TypeClass_CHAR: 375 case typelib_TypeClass_UNSIGNED_SHORT: 376 *pPT++ = 'S'; 377 break; 378 case typelib_TypeClass_BOOLEAN: 379 *pPT++ = 'B'; 380 break; 381 case typelib_TypeClass_BYTE: 382 *pPT++ = 'C'; 383 break; 384 case typelib_TypeClass_FLOAT: 385 *pPT++ = 'F'; 386 break; 387 case typelib_TypeClass_DOUBLE: 388 *pPT++ = 'D'; 389 pCppStack += sizeof(sal_Int32); // extra long 390 break; 391 case typelib_TypeClass_HYPER: 392 case typelib_TypeClass_UNSIGNED_HYPER: 393 *pPT++ = 'H'; 394 pCppStack += sizeof(sal_Int32); // extra long 395 } 396 397 // no longer needed 398 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 399 } 400 else // ptr to complex value | ref 401 { 402 if (! rParam.bIn) // is pure out 403 { 404 // cpp out is constructed mem, uno out is not! 405 uno_constructData( 406 *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ), 407 pParamTypeDescr ); 408 pTempIndizes[nTempIndizes] = nPos; // default constructed for cpp call 409 // will be released at reconversion 410 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 411 } 412 // is in/inout 413 else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr )) 414 { 415 uno_copyAndConvertData( 416 *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ), 417 pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() ); 418 419 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted 420 // will be released at reconversion 421 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 422 } 423 else // direct way 424 { 425 *(void **)pCppStack = pCppArgs[nPos] = pUnoArgs[nPos]; 426 // no longer needed 427 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 428 } 429 // KBH: FIXME: is this the right way to pass these 430 *pPT++='I'; 431 } 432 pCppStack += sizeof(sal_Int32); // standard parameter length 433 } 434 435 // terminate the signature string 436 *pPT++='X'; 437 *pPT=0; 438 439 try 440 { 441 OSL_ENSURE( !( (pCppStack - pCppStackStart ) & 3), "UNALIGNED STACK !!! (Please DO panic)" ); 442 callVirtualMethod( 443 pAdjustedThisPtr, aVtableSlot.index, 444 pCppReturn, pReturnTypeDescr->eTypeClass, pParamType, 445 (sal_Int32 *)pCppStackStart, (pCppStack - pCppStackStart) / sizeof(sal_Int32) ); 446 // NO exception occured... 447 *ppUnoExc = 0; 448 449 // reconvert temporary params 450 for ( ; nTempIndizes--; ) 451 { 452 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 453 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes]; 454 455 if (pParams[nIndex].bIn) 456 { 457 if (pParams[nIndex].bOut) // inout 458 { 459 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value 460 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr, 461 pThis->getBridge()->getCpp2Uno() ); 462 } 463 } 464 else // pure out 465 { 466 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr, 467 pThis->getBridge()->getCpp2Uno() ); 468 } 469 // destroy temp cpp param => cpp: every param was constructed 470 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release ); 471 472 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 473 } 474 // return value 475 if (pCppReturn && pUnoReturn != pCppReturn) 476 { 477 uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr, 478 pThis->getBridge()->getCpp2Uno() ); 479 uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release ); 480 } 481 } 482 catch (...) 483 { 484 // fill uno exception 485 fillUnoException( CPPU_CURRENT_NAMESPACE::__cxa_get_globals()->caughtExceptions, 486 *ppUnoExc, pThis->getBridge()->getCpp2Uno() ); 487 488 489 // temporary params 490 for ( ; nTempIndizes--; ) 491 { 492 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 493 // destroy temp cpp param => cpp: every param was constructed 494 uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], cpp_release ); 495 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] ); 496 } 497 // return type 498 if (pReturnTypeDescr) 499 TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); 500 } 501 } 502 } 503 504 namespace bridges { namespace cpp_uno { namespace shared { 505 506 void unoInterfaceProxyDispatch( 507 uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr, 508 void * pReturn, void * pArgs[], uno_Any ** ppException ) 509 { 510 #ifdef CMC_DEBUG 511 fprintf(stderr, "unoInterfaceProxyDispatch\n"); 512 #endif 513 514 515 // is my surrogate 516 bridges::cpp_uno::shared::UnoInterfaceProxy * pThis 517 = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy *> (pUnoI); 518 typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr; 519 520 switch (pMemberDescr->eTypeClass) 521 { 522 case typelib_TypeClass_INTERFACE_ATTRIBUTE: 523 { 524 525 VtableSlot aVtableSlot( 526 getVtableSlot( 527 reinterpret_cast< 528 typelib_InterfaceAttributeTypeDescription const * >( 529 pMemberDescr))); 530 531 if (pReturn) 532 { 533 // dependent dispatch 534 cpp_call( 535 pThis, aVtableSlot, 536 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef, 537 0, 0, // no params 538 pReturn, pArgs, ppException ); 539 } 540 else 541 { 542 // is SET 543 typelib_MethodParameter aParam; 544 aParam.pTypeRef = 545 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef; 546 aParam.bIn = sal_True; 547 aParam.bOut = sal_False; 548 549 typelib_TypeDescriptionReference * pReturnTypeRef = 0; 550 OUString aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") ); 551 typelib_typedescriptionreference_new( 552 &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData ); 553 554 // dependent dispatch 555 aVtableSlot.index += 1; //get then set method 556 cpp_call( 557 pThis, aVtableSlot, 558 pReturnTypeRef, 559 1, &aParam, 560 pReturn, pArgs, ppException ); 561 562 typelib_typedescriptionreference_release( pReturnTypeRef ); 563 } 564 565 break; 566 } 567 case typelib_TypeClass_INTERFACE_METHOD: 568 { 569 570 VtableSlot aVtableSlot( 571 getVtableSlot( 572 reinterpret_cast< 573 typelib_InterfaceMethodTypeDescription const * >( 574 pMemberDescr))); 575 switch (aVtableSlot.index) 576 { 577 // standard calls 578 case 1: // acquire uno interface 579 (*pUnoI->acquire)( pUnoI ); 580 *ppException = 0; 581 break; 582 case 2: // release uno interface 583 (*pUnoI->release)( pUnoI ); 584 *ppException = 0; 585 break; 586 case 0: // queryInterface() opt 587 { 588 typelib_TypeDescription * pTD = 0; 589 TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() ); 590 if (pTD) 591 { 592 uno_Interface * pInterface = 0; 593 (*pThis->pBridge->getUnoEnv()->getRegisteredInterface)( 594 pThis->pBridge->getUnoEnv(), 595 (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD ); 596 597 if (pInterface) 598 { 599 ::uno_any_construct( 600 reinterpret_cast< uno_Any * >( pReturn ), 601 &pInterface, pTD, 0 ); 602 (*pInterface->release)( pInterface ); 603 TYPELIB_DANGER_RELEASE( pTD ); 604 *ppException = 0; 605 break; 606 } 607 TYPELIB_DANGER_RELEASE( pTD ); 608 } 609 } // else perform queryInterface() 610 default: 611 // dependent dispatch 612 cpp_call( 613 pThis, aVtableSlot, 614 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef, 615 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams, 616 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams, 617 pReturn, pArgs, ppException ); 618 } 619 break; 620 } 621 default: 622 { 623 ::com::sun::star::uno::RuntimeException aExc( 624 OUString( RTL_CONSTASCII_USTRINGPARAM("illegal member type description!") ), 625 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() ); 626 627 Type const & rExcType = ::getCppuType( &aExc ); 628 // binary identical null reference 629 ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 ); 630 } 631 } 632 } 633 634 } } } 635 /* vi:set tabstop=4 shiftwidth=4 expandtab: */ 636