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 <sys/types.h> 28 #include <sys/malloc.h> 29 30 #include <com/sun/star/uno/genfunc.hxx> 31 #include <uno/data.h> 32 33 #include "bridges/cpp_uno/shared/bridge.hxx" 34 #include "bridges/cpp_uno/shared/types.hxx" 35 #include "bridges/cpp_uno/shared/unointerfaceproxy.hxx" 36 #include "bridges/cpp_uno/shared/vtables.hxx" 37 38 #include "share.hxx" 39 40 41 using namespace ::rtl; 42 using namespace ::com::sun::star::uno; 43 44 namespace 45 { 46 47 //================================================================================================== 48 static void callVirtualMethod( 49 void * pAdjustedThisPtr, 50 sal_Int32 nVtableIndex, 51 void * pRegisterReturn, 52 typelib_TypeClass eReturnType, 53 char * pPT, 54 sal_Int32 * pStackLongs, 55 sal_Int32 /* nStackLongs */) 56 { 57 58 // parameter list is mixed list of * and values 59 // reference parameters are pointers 60 61 // the basic idea here is to use gpr[8] as a storage area for 62 // the future values of registers r3 to r10 needed for the call, 63 // and similarly fpr[13] as a storage area for the future values 64 // of floating point registers f1 to f13 65 66 unsigned long * mfunc; // actual function to be invoked 67 void (*ptr)(); 68 int gpr[8]; // storage for gpregisters, map to r3-r10 69 int off; // offset used to find function 70 double fpr[13]; // storage for fpregisters, map to f1-f13 71 int n; // number of gprs mapped so far 72 int f; // number of fprs mapped so far 73 volatile long *p; // pointer to parameter overflow area 74 int c; // character of parameter type being decoded 75 volatile double dret; // temporary function return values 76 volatile int iret, iret2; 77 78 // Because of the Power PC calling conventions we could be passing 79 // parameters in both register types and on the stack. To create the 80 // stack parameter area we need we now simply allocate local 81 // variable storage param[] that is at least the size of the parameter stack 82 // (more than enough space) which we can overwrite the parameters into. 83 84 // Note: This keeps us from having to decode the signature twice and 85 // prevents problems with later local variables. 86 87 // FIXME: I do not believe the following is true but we will keep the 88 // FIXME: extra space just to be safe until proven otherwise 89 90 // Note: could require up to 2*nStackLongs words of parameter stack area 91 // if the call has many float parameters (i.e. floats take up only 1 92 // word on the stack but take 2 words in parameter area in the 93 // stack frame . 94 95 96 // unsigned long param[(2*nStackLongs)]; 97 98 /* now begin to load the C++ function arguments into storage */ 99 n = 0; 100 f = 0; 101 102 103 /* set up a pointer to the stack parameter area */ 104 __asm__ ( "addi %0,r1,24" : "=r" (p) : /* no inputs */ ); 105 106 // #i94421#, work around compiler error: 107 volatile long * pCopy = p; 108 (void) pCopy; // avoid warning about unused variable 109 110 // never called 111 // if (! pAdjustedThisPtr )CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything("xxx"); // address something 112 113 114 // now we need to parse the entire signature string 115 // until we get the END indicator 116 117 // treat complex return pointer like any other parameter 118 119 // parse the argument list up to the ending ) 120 121 while (*pPT != 'X') { 122 c = *pPT; 123 switch (c) { 124 125 case 'D': /* type is double */ 126 if (f < 13) { 127 fpr[f++] = *((double *)pStackLongs); /* store in register */ 128 n+=2; 129 p+=2; 130 } else { 131 *p++ = *pStackLongs; /* or on the parameter stack */ 132 *p++ = *(pStackLongs + 1); 133 } 134 pStackLongs += 2; 135 break; 136 137 case 'F': /* type is float */ 138 /* floats are stored as 1 32 bit word on param stack */ 139 if (f < 13) { 140 fpr[f++] = *((float *)pStackLongs); 141 n+=1; 142 p++; 143 } else { 144 *((float *)p) = *((float *)pStackLongs); 145 p += 1; 146 } 147 pStackLongs += 1; 148 break; 149 150 case 'H': /* type is long long */ 151 if (n < 8) 152 { 153 gpr[n++] = *pStackLongs; 154 p++; 155 } 156 else 157 *p++ = *pStackLongs; 158 if(n < 8) 159 { 160 gpr[n++] = *(pStackLongs+1); 161 p++; 162 } 163 else 164 *p++ = *(pStackLongs+1); 165 pStackLongs += 2; 166 break; 167 168 case 'S': 169 if (n < 8) { 170 gpr[n++] = *((unsigned short*)pStackLongs); 171 p++; 172 } else { 173 *p++ = *((unsigned short *)pStackLongs); 174 } 175 pStackLongs += 1; 176 break; 177 178 case 'B': 179 if (n < 8) { 180 gpr[n++] = *((char *)pStackLongs); 181 p++; 182 } else { 183 *p++ = *((char *)pStackLongs); 184 } 185 pStackLongs += 1; 186 break; 187 188 default: 189 if (n < 8) { 190 gpr[n++] = *pStackLongs; 191 p++; 192 } else { 193 *p++ = *pStackLongs; 194 } 195 pStackLongs += 1; 196 break; 197 } 198 pPT++; 199 } 200 201 202 /* figure out the address of the function we need to invoke */ 203 off = nVtableIndex; 204 off = off * 4; // 4 bytes per slot 205 mfunc = *((unsigned long **)pAdjustedThisPtr); // get the address of the vtable 206 mfunc = (unsigned long *)((char *)mfunc + off); // get the address from the vtable entry at offset 207 mfunc = *((unsigned long **)mfunc); // the function is stored at the address 208 ptr = (void (*)())mfunc; 209 210 /* Set up the machine registers and invoke the function */ 211 212 __asm__ __volatile__ ( 213 "lwz r3, 0(%0)\n\t" 214 "lwz r4, 4(%0)\n\t" 215 "lwz r5, 8(%0)\n\t" 216 "lwz r6, 12(%0)\n\t" 217 "lwz r7, 16(%0)\n\t" 218 "lwz r8, 20(%0)\n\t" 219 "lwz r9, 24(%0)\n\t" 220 "lwz r10, 28(%0)\n\t" 221 "lfd f1, 0(%1)\n\t" 222 "lfd f2, 8(%1)\n\t" 223 "lfd f3, 16(%1)\n\t" 224 "lfd f4, 24(%1)\n\t" 225 "lfd f5, 32(%1)\n\t" 226 "lfd f6, 40(%1)\n\t" 227 "lfd f7, 48(%1)\n\t" 228 "lfd f8, 56(%1)\n\t" 229 "lfd f9, 64(%1)\n\t" 230 "lfd f10, 72(%1)\n\t" 231 "lfd f11, 80(%1)\n\t" 232 "lfd f12, 88(%1)\n\t" 233 "lfd f13, 96(%1)\n\t" 234 : : "r" (gpr), "r" (fpr) 235 : "r0", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", 236 "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", 237 "f10", "f11", "f12", "f13" 238 ); 239 240 (*ptr)(); 241 242 243 __asm__ __volatile__ ( 244 "stw r3, %1\n\t" 245 "stw r4, %2\n\t" 246 "stfd f1, %0\n\t" 247 : : "m" (dret), "m" (iret), "m" (iret2) 248 ); 249 250 251 switch( eReturnType ) 252 { 253 case typelib_TypeClass_HYPER: 254 case typelib_TypeClass_UNSIGNED_HYPER: 255 ((long*)pRegisterReturn)[1] = iret2; 256 // fall thru on purpose 257 case typelib_TypeClass_LONG: 258 case typelib_TypeClass_UNSIGNED_LONG: 259 case typelib_TypeClass_ENUM: 260 ((long*)pRegisterReturn)[0] = iret; 261 break; 262 263 case typelib_TypeClass_CHAR: 264 case typelib_TypeClass_SHORT: 265 case typelib_TypeClass_UNSIGNED_SHORT: 266 *(unsigned short*)pRegisterReturn = (unsigned short)iret; 267 break; 268 269 case typelib_TypeClass_BOOLEAN: 270 case typelib_TypeClass_BYTE: 271 *(unsigned char*)pRegisterReturn = (unsigned char)iret; 272 break; 273 274 case typelib_TypeClass_FLOAT: 275 *(float*)pRegisterReturn = (float)dret; 276 break; 277 278 case typelib_TypeClass_DOUBLE: 279 *(double*)pRegisterReturn = dret; 280 break; 281 default: 282 break; 283 } 284 } 285 286 287 //================================================================================================== 288 static void cpp_call( 289 bridges::cpp_uno::shared::UnoInterfaceProxy * pThis, 290 bridges::cpp_uno::shared::VtableSlot aVtableSlot, 291 typelib_TypeDescriptionReference * pReturnTypeRef, 292 sal_Int32 nParams, typelib_MethodParameter * pParams, 293 void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc ) 294 { 295 // max space for: [complex ret ptr], values|ptr ... 296 char * pCppStack = 297 (char *)alloca( sizeof(sal_Int32) + ((nParams+2) * sizeof(sal_Int64)) ); 298 char * pCppStackStart = pCppStack; 299 300 // need to know parameter types for callVirtualMethod so generate a signature string 301 char * pParamType = (char *) alloca(nParams+2); 302 char * pPT = pParamType; 303 304 // return 305 typelib_TypeDescription * pReturnTypeDescr = 0; 306 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef ); 307 OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" ); 308 309 void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion 310 311 if (pReturnTypeDescr) 312 { 313 if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr )) 314 { 315 pCppReturn = pUnoReturn; // direct way for simple types 316 } 317 else 318 { 319 // complex return via ptr 320 pCppReturn = *(void **)pCppStack 321 = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr ) 322 ? alloca( pReturnTypeDescr->nSize ) 323 : pUnoReturn); // direct way 324 *pPT++ = 'C'; //signify that a complex return type on stack 325 pCppStack += sizeof(void *); 326 } 327 } 328 // push this 329 void * pAdjustedThisPtr = reinterpret_cast< void ** >(pThis->getCppI()) 330 + aVtableSlot.offset; 331 *(void**)pCppStack = pAdjustedThisPtr; 332 pCppStack += sizeof( void* ); 333 *pPT++ = 'I'; 334 335 // stack space 336 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" ); 337 // args 338 void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams ); 339 // indizes of values this have to be converted (interface conversion cpp<=>uno) 340 sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams); 341 // type descriptions for reconversions 342 typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams)); 343 344 sal_Int32 nTempIndizes = 0; 345 346 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) 347 { 348 const typelib_MethodParameter & rParam = pParams[nPos]; 349 typelib_TypeDescription * pParamTypeDescr = 0; 350 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef ); 351 352 if (!rParam.bOut 353 && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr )) 354 { 355 uno_copyAndConvertData( pCppArgs[nPos] = pCppStack, pUnoArgs[nPos], pParamTypeDescr, 356 pThis->getBridge()->getUno2Cpp() ); 357 358 switch (pParamTypeDescr->eTypeClass) 359 { 360 361 // we need to know type of each param so that we know whether to use 362 // gpr or fpr to pass in parameters: 363 // Key: I - int, long, pointer, etc means pass in gpr 364 // B - byte value passed in gpr 365 // S - short value passed in gpr 366 // F - float value pass in fpr 367 // D - double value pass in fpr 368 // H - long long int pass in proper pairs of gpr (3,4) (5,6), etc 369 // X - indicates end of parameter description string 370 371 case typelib_TypeClass_LONG: 372 case typelib_TypeClass_UNSIGNED_LONG: 373 case typelib_TypeClass_ENUM: 374 *pPT++ = 'I'; 375 break; 376 case typelib_TypeClass_SHORT: 377 case typelib_TypeClass_CHAR: 378 case typelib_TypeClass_UNSIGNED_SHORT: 379 *pPT++ = 'S'; 380 break; 381 case typelib_TypeClass_BOOLEAN: 382 case typelib_TypeClass_BYTE: 383 *pPT++ = 'B'; 384 break; 385 case typelib_TypeClass_FLOAT: 386 *pPT++ = 'F'; 387 break; 388 case typelib_TypeClass_DOUBLE: 389 *pPT++ = 'D'; 390 pCppStack += sizeof(sal_Int32); // extra long 391 break; 392 case typelib_TypeClass_HYPER: 393 case typelib_TypeClass_UNSIGNED_HYPER: 394 *pPT++ = 'H'; 395 pCppStack += sizeof(sal_Int32); // extra long 396 default: 397 break; 398 } 399 400 // no longer needed 401 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 402 } 403 else // ptr to complex value | ref 404 { 405 if (! rParam.bIn) // is pure out 406 { 407 // cpp out is constructed mem, uno out is not! 408 uno_constructData( 409 *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ), 410 pParamTypeDescr ); 411 pTempIndizes[nTempIndizes] = nPos; // default constructed for cpp call 412 // will be released at reconversion 413 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 414 } 415 // is in/inout 416 else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr )) 417 { 418 uno_copyAndConvertData( 419 *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ), 420 pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() ); 421 422 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted 423 // will be released at reconversion 424 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 425 } 426 else // direct way 427 { 428 *(void **)pCppStack = pCppArgs[nPos] = pUnoArgs[nPos]; 429 // no longer needed 430 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 431 } 432 *pPT++='I'; 433 } 434 pCppStack += sizeof(sal_Int32); // standard parameter length 435 } 436 437 // terminate the signature string 438 *pPT++='X'; 439 *pPT=0; 440 441 try 442 { 443 OSL_ENSURE( !( (pCppStack - pCppStackStart ) & 3), "UNALIGNED STACK !!! (Please DO panic)" ); 444 callVirtualMethod( 445 pAdjustedThisPtr, aVtableSlot.index, 446 pCppReturn, pReturnTypeDescr->eTypeClass, pParamType, 447 (sal_Int32 *)pCppStackStart, (pCppStack - pCppStackStart) / sizeof(sal_Int32) ); 448 // NO exception occured... 449 *ppUnoExc = 0; 450 451 // reconvert temporary params 452 for ( ; nTempIndizes--; ) 453 { 454 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 455 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes]; 456 457 if (pParams[nIndex].bIn) 458 { 459 if (pParams[nIndex].bOut) // inout 460 { 461 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value 462 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr, 463 pThis->getBridge()->getCpp2Uno() ); 464 } 465 } 466 else // pure out 467 { 468 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr, 469 pThis->getBridge()->getCpp2Uno() ); 470 } 471 // destroy temp cpp param => cpp: every param was constructed 472 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release ); 473 474 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 475 } 476 // return value 477 if (pCppReturn && pUnoReturn != pCppReturn) 478 { 479 uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr, 480 pThis->getBridge()->getCpp2Uno() ); 481 uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release ); 482 } 483 } 484 catch (...) 485 { 486 // fill uno exception 487 fillUnoException( CPPU_CURRENT_NAMESPACE::__cxa_get_globals()->caughtExceptions, *ppUnoExc, pThis->getBridge()->getCpp2Uno() ); 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 505 namespace bridges { namespace cpp_uno { namespace shared { 506 507 void unoInterfaceProxyDispatch( 508 uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr, 509 void * pReturn, void * pArgs[], uno_Any ** ppException ) 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