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 #include <com/sun/star/uno/genfunc.hxx> 28 #include <typelib/typedescription.hxx> 29 #include <uno/data.h> 30 #include <osl/endian.h> 31 #include "bridges/cpp_uno/shared/bridge.hxx" 32 #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx" 33 #include "bridges/cpp_uno/shared/types.hxx" 34 #include "bridges/cpp_uno/shared/vtablefactory.hxx" 35 #include "share.hxx" 36 37 #include <stdio.h> 38 #include <string.h> 39 40 using namespace com::sun::star::uno; 41 42 //#define BRDEBUG 43 44 #ifdef BRDEBUG 45 #include <rtl/strbuf.hxx> 46 #include <rtl/ustrbuf.hxx> 47 #include <osl/diagnose.h> 48 #include <osl/mutex.hxx> 49 using namespace ::std; 50 using namespace ::osl; 51 using namespace ::rtl; 52 #endif 53 #include <sys/sysmips.h> 54 55 #ifdef OSL_BIGENDIAN 56 #define IS_BIG_ENDIAN 1 57 #else 58 #define IS_BIG_ENDIAN 0 59 #endif 60 61 using namespace ::com::sun::star::uno; 62 63 namespace 64 { 65 66 //================================================================================================== 67 static typelib_TypeClass cpp2uno_call( 68 bridges::cpp_uno::shared::CppInterfaceProxy * pThis, 69 const typelib_TypeDescription * pMemberTypeDescr, 70 typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return 71 sal_Int32 nParams, typelib_MethodParameter * pParams, 72 void ** gpreg, void ** /*fpreg*/, void ** ovrflw, 73 sal_Int64 * pRegisterReturn /* space for register return */ ) 74 { 75 /* Most MIPS ABIs view the arguments as a struct, of which the 76 first N words go in registers and the rest go on the stack. If I < N, the 77 Ith word might go in Ith integer argument register or the Ith 78 floating-point one. For these ABIs, we only need to remember the number 79 of words passed so far. We are interested only in o32 ABI,so it is the 80 case. 81 */ 82 int nw = 0; // number of words used by arguments 83 84 #ifdef BRDEBUG 85 fprintf(stderr,"cpp2uno_call1\n"); 86 #endif 87 88 /* C++ has [ret *] or this as the first arguments, so no arguments will 89 * be passed in floating-point registers? 90 */ 91 //int int_seen = 0; // have we seen integer arguments? 92 93 void ** pCppStack; //temporary stack pointer 94 95 // gpreg: [ret *], this, [gpr params] 96 // fpreg: [fpr params] 97 // ovrflw: [gpr or fpr params (properly aligned)] 98 99 // return 100 typelib_TypeDescription * pReturnTypeDescr = 0; 101 if (pReturnTypeRef) 102 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef ); 103 104 void * pUnoReturn = 0; 105 void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need 106 107 if (pReturnTypeDescr) 108 { 109 if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr )) 110 { 111 pUnoReturn = pRegisterReturn; // direct way for simple types 112 #ifdef BRDEBUG 113 fprintf(stderr,"cpp2uno_call:simplereturn\n"); 114 #endif 115 } 116 else // complex return via ptr (pCppReturn) 117 { 118 pCppReturn = *(void **)gpreg; 119 gpreg++; 120 nw++; 121 122 pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr ) 123 ? alloca( pReturnTypeDescr->nSize ) 124 : pCppReturn); // direct way 125 #ifdef BRDEBUG 126 fprintf(stderr,"cpp2uno_call:complexreturn\n"); 127 #endif 128 } 129 } 130 131 // pop this 132 gpreg++; 133 nw++; 134 135 // stack space 136 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" ); 137 // parameters 138 void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams ); 139 void ** pCppArgs = pUnoArgs + nParams; 140 // indizes of values this have to be converted (interface conversion cpp<=>uno) 141 sal_Int32 * pTempIndizes = (sal_Int32 *)(pUnoArgs + (2 * nParams)); 142 // type descriptions for reconversions 143 typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams)); 144 145 sal_Int32 nTempIndizes = 0; 146 147 #ifdef BRDEBUG 148 fprintf(stderr,"cpp2uno_call:nParams=%d\n",nParams); 149 #endif 150 151 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) 152 { 153 const typelib_MethodParameter & rParam = pParams[nPos]; 154 typelib_TypeDescription * pParamTypeDescr = 0; 155 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef ); 156 157 if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr )) 158 // value 159 { 160 161 switch (pParamTypeDescr->eTypeClass) 162 { 163 case typelib_TypeClass_DOUBLE: 164 case typelib_TypeClass_HYPER: 165 case typelib_TypeClass_UNSIGNED_HYPER: 166 #ifdef BRDEBUG 167 fprintf(stderr,"cpp2uno_call:hyper=%d,%p\n",pParamTypeDescr->eTypeClass,gpreg[0]); 168 #endif 169 if (nw < 3) { 170 if (nw & 1) { 171 nw++; 172 gpreg++; 173 } 174 #ifdef BRDEBUG 175 fprintf(stderr,"cpp2uno_call:gpreg=%p,%p\n",gpreg[0],gpreg[1]); 176 #endif 177 pCppArgs[nPos] = gpreg; 178 pUnoArgs[nPos] = gpreg; 179 nw += 2; 180 gpreg += 2; 181 } else { 182 if (((long)ovrflw) & 4) ovrflw++; 183 #ifdef BRDEBUG 184 fprintf(stderr,"cpp2uno_call:overflw=%p,%p\n",ovrflw[0],ovrflw[1]); 185 #endif 186 pCppArgs[nPos] = ovrflw; 187 pUnoArgs[nPos] = ovrflw; 188 ovrflw += 2; 189 } 190 break; 191 192 case typelib_TypeClass_BYTE: 193 case typelib_TypeClass_BOOLEAN: 194 #ifdef BRDEBUG 195 fprintf(stderr,"cpp2uno_call:byte=%p,%p\n",gpreg[0],ovrflw[0]); 196 #endif 197 if (nw < 4) { 198 pCppArgs[nPos] = ((char *)gpreg + 3*IS_BIG_ENDIAN); 199 pUnoArgs[nPos] = ((char *)gpreg + 3*IS_BIG_ENDIAN); 200 nw++; 201 gpreg++; 202 } else { 203 pCppArgs[nPos] = ((char *)ovrflw + 3*IS_BIG_ENDIAN); 204 pUnoArgs[nPos] = ((char *)ovrflw + 3*IS_BIG_ENDIAN); 205 ovrflw++; 206 } 207 break; 208 209 210 case typelib_TypeClass_CHAR: 211 case typelib_TypeClass_SHORT: 212 case typelib_TypeClass_UNSIGNED_SHORT: 213 #ifdef BRDEBUG 214 fprintf(stderr,"cpp2uno_call:char=%p,%p\n",gpreg[0],ovrflw[0]); 215 #endif 216 if (nw < 4) { 217 pCppArgs[nPos] = ((char *)gpreg + 2*IS_BIG_ENDIAN); 218 pUnoArgs[nPos] = ((char *)gpreg + 2*IS_BIG_ENDIAN); 219 nw++; 220 gpreg++; 221 } else { 222 pCppArgs[nPos] = ((char *)ovrflw + 2*IS_BIG_ENDIAN); 223 pUnoArgs[nPos] = ((char *)ovrflw + 2*IS_BIG_ENDIAN); 224 ovrflw++; 225 } 226 break; 227 228 229 default: 230 #ifdef BRDEBUG 231 fprintf(stderr,"cpp2uno_call:def=%p,%p\n",gpreg[0],ovrflw[0]); 232 #endif 233 if (nw < 4) { 234 pCppArgs[nPos] = gpreg; 235 pUnoArgs[nPos] = gpreg; 236 nw++; 237 gpreg++; 238 } else { 239 pCppArgs[nPos] = ovrflw; 240 pUnoArgs[nPos] = ovrflw; 241 ovrflw++; 242 } 243 break; 244 245 } 246 // no longer needed 247 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 248 } 249 else // ptr to complex value | ref 250 { 251 252 #ifdef BRDEBUG 253 fprintf(stderr,"cpp2uno_call:ptr|ref\n"); 254 #endif 255 if (nw < 4) { 256 pCppArgs[nPos] = *(void **)gpreg; 257 pCppStack = gpreg; 258 nw++; 259 gpreg++; 260 } else { 261 pCppArgs[nPos] = *(void **)ovrflw; 262 pCppStack = ovrflw; 263 ovrflw++; 264 } 265 #ifdef BRDEBUG 266 fprintf(stderr,"cpp2uno_call:pCppStack=%p\n",pCppStack); 267 #endif 268 269 if (! rParam.bIn) // is pure out 270 { 271 // uno out is unconstructed mem! 272 pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ); 273 pTempIndizes[nTempIndizes] = nPos; 274 // will be released at reconversion 275 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 276 } 277 // is in/inout 278 else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr )) 279 { 280 uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ), 281 *(void **)pCppStack, pParamTypeDescr, 282 pThis->getBridge()->getCpp2Uno() ); 283 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted 284 // will be released at reconversion 285 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 286 #ifdef BRDEBUG 287 fprintf(stderr,"cpp2uno_call:related to interface,%p,%d,pUnoargs[%d]=%p\n",*(void**)pCppStack,pParamTypeDescr->nSize,nPos,pUnoArgs[nPos]); 288 #endif 289 } 290 else // direct way 291 { 292 pUnoArgs[nPos] = *(void **)pCppStack; 293 #ifdef BRDEBUG 294 fprintf(stderr,"cpp2uno_call:direct,pUnoArgs[%d]=%p\n",nPos,pUnoArgs[nPos]); 295 #endif 296 // no longer needed 297 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 298 } 299 } 300 } 301 #ifdef BRDEBUG 302 fprintf(stderr,"cpp2uno_call2,%p,unoargs=%p\n",pThis->getUnoI()->pDispatcher,pUnoArgs); 303 #endif 304 305 // ExceptionHolder 306 uno_Any aUnoExc; // Any will be constructed by callee 307 uno_Any * pUnoExc = &aUnoExc; 308 309 // invoke uno dispatch call 310 (*pThis->getUnoI()->pDispatcher)( pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc ); 311 #ifdef BRDEBUG 312 fprintf(stderr,"cpp2uno_call2,after dispatch\n"); 313 #endif 314 315 // in case an exception occured... 316 if (pUnoExc) 317 { 318 // destruct temporary in/inout params 319 for ( ; nTempIndizes--; ) 320 { 321 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 322 323 if (pParams[nIndex].bIn) // is in/inout => was constructed 324 uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], 0 ); 325 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] ); 326 } 327 if (pReturnTypeDescr) 328 TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); 329 330 CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc, pThis->getBridge()->getUno2Cpp() ); 331 // has to destruct the any 332 // is here for dummy 333 return typelib_TypeClass_VOID; 334 } 335 else // else no exception occured... 336 { 337 // temporary params 338 for ( ; nTempIndizes--; ) 339 { 340 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 341 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes]; 342 343 if (pParams[nIndex].bOut) // inout/out 344 { 345 // convert and assign 346 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release ); 347 uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr, 348 pThis->getBridge()->getUno2Cpp() ); 349 } 350 // destroy temp uno param 351 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); 352 353 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 354 } 355 // return 356 if (pCppReturn) // has complex return 357 { 358 if (pUnoReturn != pCppReturn) // needs reconversion 359 { 360 uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr, 361 pThis->getBridge()->getUno2Cpp() ); 362 // destroy temp uno return 363 uno_destructData( pUnoReturn, pReturnTypeDescr, 0 ); 364 } 365 // complex return ptr is set to return reg 366 *(void **)pRegisterReturn = pCppReturn; 367 } 368 if (pReturnTypeDescr) 369 { 370 typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass; 371 TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); 372 return eRet; 373 } 374 else 375 return typelib_TypeClass_VOID; 376 } 377 } 378 379 380 //================================================================================================== 381 static typelib_TypeClass cpp_mediate( 382 sal_Int32 nFunctionIndex, 383 sal_Int32 nVtableOffset, 384 void ** gpreg, void ** fpreg, void ** ovrflw, 385 sal_Int64 * pRegisterReturn /* space for register return */ ) 386 { 387 OSL_ENSURE( sizeof(sal_Int32)==sizeof(void *), "### unexpected!" ); 388 389 #ifdef BRDEBUG 390 fprintf(stderr,"cpp_mediate1 gp=%p,fp=%p,ov=%p\n",gpreg,fpreg,ovrflw); 391 fprintf(stderr,"gp=%x,%x,%x,%x\n",gpreg[0],gpreg[1],gpreg[2],gpreg[3]); 392 #endif 393 394 // gpreg: [ret *], this, [other gpr params] 395 // fpreg: [fpr params] 396 // ovrflw: [gpr or fpr params (properly aligned)] 397 398 void * pThis; 399 if (nFunctionIndex & 0x80000000 ) 400 { 401 nFunctionIndex &= 0x7fffffff; 402 pThis = gpreg[1]; 403 } 404 else 405 { 406 pThis = gpreg[0]; 407 } 408 #ifdef BRDEBUG 409 fprintf(stderr,"cpp_mediate12,pThis=%p, nFunctionIndex=%d,nVtableOffset=%d\n",pThis,nFunctionIndex,nVtableOffset); 410 #endif 411 412 pThis = static_cast< char * >(pThis) - nVtableOffset; 413 bridges::cpp_uno::shared::CppInterfaceProxy * pCppI 414 = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( 415 pThis); 416 #ifdef BRDEBUG 417 fprintf(stderr,"cpp_mediate13,pCppI=%p\n",pCppI); 418 #endif 419 420 typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr(); 421 422 #ifdef BRDEBUG 423 fprintf(stderr,"cpp_mediate2\n"); 424 #endif 425 OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!" ); 426 if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex) 427 { 428 throw RuntimeException( 429 rtl::OUString::createFromAscii("illegal vtable index!"), 430 (XInterface *)pThis ); 431 } 432 433 // determine called method 434 sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex]; 435 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!" ); 436 437 TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] ); 438 439 #ifdef BRDEBUG 440 fprintf(stderr,"cpp_mediate3\n"); 441 OString cstr( OUStringToOString( aMemberDescr.get()->pTypeName, RTL_TEXTENCODING_ASCII_US ) ); 442 fprintf( stderr, "calling %s, nFunctionIndex=%d\n", cstr.getStr(), nFunctionIndex ); 443 #endif 444 typelib_TypeClass eRet; 445 switch (aMemberDescr.get()->eTypeClass) 446 { 447 case typelib_TypeClass_INTERFACE_ATTRIBUTE: 448 { 449 #ifdef BRDEBUG 450 fprintf(stderr,"cpp_mediate4\n"); 451 #endif 452 if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex) 453 { 454 // is GET method 455 eRet = cpp2uno_call( 456 pCppI, aMemberDescr.get(), 457 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef, 458 0, 0, // no params 459 gpreg, fpreg, ovrflw, pRegisterReturn ); 460 } 461 else 462 { 463 // is SET method 464 typelib_MethodParameter aParam; 465 aParam.pTypeRef = 466 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef; 467 aParam.bIn = sal_True; 468 aParam.bOut = sal_False; 469 470 eRet = cpp2uno_call( 471 pCppI, aMemberDescr.get(), 472 0, // indicates void return 473 1, &aParam, 474 gpreg, fpreg, ovrflw, pRegisterReturn ); 475 } 476 break; 477 } 478 case typelib_TypeClass_INTERFACE_METHOD: 479 { 480 #ifdef BRDEBUG 481 fprintf(stderr,"cpp_mediate5\n"); 482 #endif 483 // is METHOD 484 switch (nFunctionIndex) 485 { 486 case 1: // acquire() 487 pCppI->acquireProxy(); // non virtual call! 488 eRet = typelib_TypeClass_VOID; 489 break; 490 case 2: // release() 491 #ifdef BRDEBUG 492 fprintf(stderr,"cpp_mediate51\n"); 493 #endif 494 pCppI->releaseProxy(); // non virtual call! 495 eRet = typelib_TypeClass_VOID; 496 #ifdef BRDEBUG 497 fprintf(stderr,"cpp_mediate52\n"); 498 #endif 499 break; 500 case 0: // queryInterface() opt 501 { 502 typelib_TypeDescription * pTD = 0; 503 TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( gpreg[2] )->getTypeLibType() ); 504 if (pTD) 505 { 506 XInterface * pInterface = 0; 507 (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)( 508 pCppI->getBridge()->getCppEnv(), 509 (void **)&pInterface, pCppI->getOid().pData, 510 (typelib_InterfaceTypeDescription *)pTD ); 511 512 if (pInterface) 513 { 514 ::uno_any_construct( 515 reinterpret_cast< uno_Any * >( gpreg[0] ), 516 &pInterface, pTD, cpp_acquire ); 517 pInterface->release(); 518 TYPELIB_DANGER_RELEASE( pTD ); 519 *(void **)pRegisterReturn = gpreg[0]; 520 eRet = typelib_TypeClass_ANY; 521 break; 522 } 523 TYPELIB_DANGER_RELEASE( pTD ); 524 } 525 } // else perform queryInterface() 526 default: 527 eRet = cpp2uno_call( 528 pCppI, aMemberDescr.get(), 529 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef, 530 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams, 531 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams, 532 gpreg, fpreg, ovrflw, pRegisterReturn ); 533 } 534 break; 535 } 536 default: 537 { 538 #ifdef BRDEBUG 539 fprintf(stderr,"cpp_mediate6\n"); 540 #endif 541 throw RuntimeException( 542 rtl::OUString::createFromAscii("no member description found!"), 543 (XInterface *)pThis ); 544 // is here for dummy 545 eRet = typelib_TypeClass_VOID; 546 } 547 } 548 549 return eRet; 550 } 551 552 //================================================================================================== 553 /** 554 * is called on incoming vtable calls 555 * (called by asm snippets) 556 */ 557 // static void cpp_vtable_call( int nFunctionIndex, int nVtableOffset, void** gpregptr, void** fpregptr, void** ovrflw) 558 // static void cpp_vtable_call( int nFunctionIndex, int nVtableOffset, void** gpregptr, void** ovrflw) 559 static void cpp_vtable_call(void) 560 { 561 int nFunctionIndex; 562 int vTableOffset; 563 void** pCallStack; 564 void** ovrflw; 565 566 sal_Int32 gpreg[4]; 567 double fpreg[2]; 568 569 //memcpy( fpreg, fpregptr, 16); 570 571 volatile long nRegReturn[2]; 572 573 __asm__( "sw $4, %0\n\t" 574 "sw $5, %1\n\t" 575 "sw $6, %2\n\t" 576 "sw $7, %3\n\t" 577 ::"m"(nFunctionIndex), "m"(vTableOffset), "m"(pCallStack), "m"(ovrflw) ); 578 579 memcpy( gpreg, pCallStack, 16); 580 581 #ifdef BRDEBUG 582 fprintf(stderr,"in cpp_vtable_call nFunctionIndex is %d\n",nFunctionIndex); 583 fprintf(stderr,"in cpp_vtable_call nVtableOffset is %d\n",vTableOffset); 584 fprintf(stderr,"gp=%x,%x,%x,%x\n",gpreg[0],gpreg[1],gpreg[2],gpreg[3]); 585 #endif 586 587 //sal_Bool bComplex = nFunctionIndex & 0x80000000 ? sal_True : sal_False; 588 589 typelib_TypeClass aType = 590 cpp_mediate( nFunctionIndex, vTableOffset, (void**)gpreg, (void**)fpreg, ovrflw, (sal_Int64*)nRegReturn ); 591 592 switch( aType ) 593 { 594 595 // move return value into register space 596 // (will be loaded by machine code snippet) 597 598 case typelib_TypeClass_BOOLEAN: 599 case typelib_TypeClass_BYTE: 600 __asm__( "lbu $2,%0\n\t" : : 601 "m"(nRegReturn[0]) ); 602 break; 603 604 case typelib_TypeClass_CHAR: 605 case typelib_TypeClass_UNSIGNED_SHORT: 606 __asm__( "lhu $2,%0\n\t" : : 607 "m"(nRegReturn[0]) ); 608 break; 609 610 case typelib_TypeClass_SHORT: 611 __asm__( "lh $2,%0\n\t" : : 612 "m"(nRegReturn[0]) ); 613 break; 614 615 616 case typelib_TypeClass_FLOAT: 617 __asm__( "lwc1 $f0,%0\n\t" : : 618 "m" (*((float*)nRegReturn)) ); 619 break; 620 621 case typelib_TypeClass_DOUBLE: 622 { register double dret asm("$f0"); 623 dret = (*((double*)nRegReturn)); } 624 break; 625 626 case typelib_TypeClass_HYPER: 627 case typelib_TypeClass_UNSIGNED_HYPER: 628 __asm__( "lw $3,%0\n\t" : : 629 "m"(nRegReturn[1]) ); // fall through 630 631 default: 632 __asm__( "lw $2,%0\n\t" : : 633 "m"(nRegReturn[0]) ); 634 break; 635 } 636 } 637 638 639 int const codeSnippetSize = 56; 640 641 unsigned char * codeSnippet( unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset, 642 bool simpleRetType) 643 { 644 645 #ifdef BRDEBUG 646 fprintf(stderr,"in codeSnippet functionIndex is %d\n", functionIndex); 647 fprintf(stderr,"in codeSnippet vtableOffset is %d\n", vtableOffset); 648 fflush(stderr); 649 #endif 650 651 if (! simpleRetType ) 652 functionIndex |= 0x80000000; 653 654 unsigned long * p = (unsigned long *) code; 655 656 // OSL_ASSERT( sizeof (long) == 4 ); 657 OSL_ASSERT((((unsigned long)code) & 0x3) == 0 ); //aligned to 4 otherwise a mistake 658 659 /* generate this code */ 660 /* 661 #save regs into argument space required by mips abi 662 c: afa40000 sw a0,0(sp) 663 10: afa50004 sw a1,4(sp) 664 14: afa60008 sw a2,8(sp) 665 18: afa7000c sw a3,12(sp) 666 #a0=index 667 1c: 3c040000 lui a0,0x0 668 20: 34840000 ori a0,a0,0x0 669 #a1=offset 670 24: 3c050000 lui a1,0x0 671 28: 34a50000 ori a1,a1,0x0 672 #a2=gpregptr 673 2c: 27a60000 addiu a2,sp,0 674 #a3=ovrflw 675 30: 27a70010 addiu a3,sp,16 676 #load cpp_vtable_call addr 677 34: 3c190000 lui t9,0x0 678 38: 37390000 ori t9,t9,0 679 #jmp to the function,note: we don't use jalr, that will destroy $ra 680 #but be sure to use t9! gp calculation depends on it 681 3c: 03200008 jr t9 682 40: 00000000 nop 683 684 be careful, we use the argument space reserved by the caller to 685 write down regs. This can avoid the need to make use of arbitary far away 686 stack space or to allocate a function frame for this code snippet itself. 687 Since only functions with variable arguments will overwrite the space, 688 cpp_vtable_call should be safe. 689 ??? gcc seems change this behavior! cpp_vtable_call overwrite the space! 690 */ 691 692 * p++ = 0xafa40000; 693 * p++ = 0xafa50004; 694 * p++ = 0xafa60008; 695 * p++ = 0xafa7000c; 696 * p++ = 0x3c040000 | ((functionIndex>>16) & 0x0000ffff); 697 * p++ = 0x34840000 | (functionIndex & 0x0000ffff); 698 * p++ = 0x3c050000 | ((vtableOffset>>16) & 0x0000ffff); 699 * p++ = 0x34a50000 | (vtableOffset & 0x0000ffff); 700 * p++ = 0x27a60000; 701 * p++ = 0x27a70010; 702 * p++ = 0x3c190000 | ((((unsigned long)cpp_vtable_call) >> 16) & 0x0000ffff); 703 * p++ = 0x37390000 | (((unsigned long)cpp_vtable_call) & 0x0000FFFF); 704 * p++ = 0x03200008; 705 * p++ = 0x00000000; 706 return (code + codeSnippetSize); 707 708 } 709 710 711 } 712 713 714 #define MIN_LINE_SIZE 32 715 716 void bridges::cpp_uno::shared::VtableFactory::flushCode(unsigned char const * /*bptr*/, unsigned char const * /*eptr*/) 717 { 718 sysmips(FLUSH_CACHE,0,0,0); 719 } 720 721 struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; 722 723 bridges::cpp_uno::shared::VtableFactory::Slot * 724 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) 725 { 726 return static_cast< Slot * >(block) + 2; 727 } 728 729 730 sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize( 731 sal_Int32 slotCount) 732 { 733 return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize; 734 } 735 736 bridges::cpp_uno::shared::VtableFactory::Slot * 737 bridges::cpp_uno::shared::VtableFactory::initializeBlock( 738 void * block, sal_Int32 slotCount) 739 { 740 Slot * slots = mapBlockToVtable(block); 741 slots[-2].fn = 0; //null 742 slots[-1].fn = 0; //destructor 743 return slots + slotCount; 744 } 745 746 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions( 747 Slot ** slots, unsigned char * code, sal_PtrDiff writetoexecdiff, 748 typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset, 749 sal_Int32 functionCount, sal_Int32 vtableOffset) 750 { 751 (*slots) -= functionCount; 752 Slot * s = *slots; 753 #ifdef BRDEBUG 754 fprintf(stderr, "in addLocalFunctions functionOffset is %d\n",functionOffset); 755 fprintf(stderr, "in addLocalFunctions vtableOffset is %d\n",vtableOffset); 756 fprintf(stderr, "nMembers=%d\n",type->nMembers); 757 fflush(stderr); 758 #endif 759 760 for (sal_Int32 i = 0; i < type->nMembers; ++i) { 761 typelib_TypeDescription * member = 0; 762 TYPELIB_DANGER_GET(&member, type->ppMembers[i]); 763 OSL_ASSERT(member != 0); 764 switch (member->eTypeClass) { 765 case typelib_TypeClass_INTERFACE_ATTRIBUTE: 766 // Getter: 767 (s++)->fn = code + writetoexecdiff; 768 code = codeSnippet( 769 code, functionOffset++, vtableOffset, 770 bridges::cpp_uno::shared::isSimpleType( 771 reinterpret_cast< 772 typelib_InterfaceAttributeTypeDescription * >( 773 member)->pAttributeTypeRef)); 774 775 // Setter: 776 if (!reinterpret_cast< 777 typelib_InterfaceAttributeTypeDescription * >( 778 member)->bReadOnly) 779 { 780 (s++)->fn = code + writetoexecdiff; 781 code = codeSnippet(code, functionOffset++, vtableOffset, true); 782 } 783 break; 784 785 case typelib_TypeClass_INTERFACE_METHOD: 786 (s++)->fn = code + writetoexecdiff; 787 code = codeSnippet( 788 code, functionOffset++, vtableOffset, 789 bridges::cpp_uno::shared::isSimpleType( 790 reinterpret_cast< 791 typelib_InterfaceMethodTypeDescription * >( 792 member)->pReturnTypeRef)); 793 break; 794 795 default: 796 OSL_ASSERT(false); 797 break; 798 } 799 TYPELIB_DANGER_RELEASE(member); 800 } 801 return code; 802 } 803 804