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