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 #include <malloc.h> 29 #include <rtl/alloc.h> 30 31 #include <com/sun/star/uno/genfunc.hxx> 32 #include "com/sun/star/uno/RuntimeException.hpp" 33 #include <uno/data.h> 34 35 #include <bridges/cpp_uno/shared/bridge.hxx> 36 #include <bridges/cpp_uno/shared/types.hxx> 37 #include <bridges/cpp_uno/shared/unointerfaceproxy.hxx> 38 #include <bridges/cpp_uno/shared/vtables.hxx> 39 40 #include "share.hxx" 41 42 #include <stdio.h> 43 #include <string.h> 44 45 using namespace ::rtl; 46 using namespace ::com::sun::star::uno; 47 48 void MapReturn(long d0, long d1, typelib_TypeClass eReturnType, long *pRegisterReturn) 49 { 50 register float fret asm("fp0"); 51 register double dret asm("fp0"); 52 53 switch( eReturnType ) 54 { 55 case typelib_TypeClass_HYPER: 56 case typelib_TypeClass_UNSIGNED_HYPER: 57 pRegisterReturn[1] = d1; 58 case typelib_TypeClass_LONG: 59 case typelib_TypeClass_UNSIGNED_LONG: 60 case typelib_TypeClass_ENUM: 61 case typelib_TypeClass_CHAR: 62 case typelib_TypeClass_SHORT: 63 case typelib_TypeClass_UNSIGNED_SHORT: 64 case typelib_TypeClass_BOOLEAN: 65 case typelib_TypeClass_BYTE: 66 pRegisterReturn[0] = d0; 67 break; 68 case typelib_TypeClass_FLOAT: 69 *(float*)pRegisterReturn = fret; 70 break; 71 case typelib_TypeClass_DOUBLE: 72 *(double*)pRegisterReturn = dret; 73 break; 74 default: 75 break; 76 } 77 } 78 79 namespace 80 { 81 //================================================================ 82 83 void callVirtualMethod( 84 void * pThis, 85 sal_Int32 nVtableIndex, 86 void * pRegisterReturn, 87 typelib_TypeClass eReturnType, 88 sal_uInt32 *pStack, 89 sal_uInt32 nStack) __attribute__((noinline)); 90 91 void callVirtualMethod( 92 void * pThis, 93 sal_Int32 nVtableIndex, 94 void * pRegisterReturn, 95 typelib_TypeClass eReturnType, 96 sal_uInt32 *pStack, 97 sal_uInt32 nStack) 98 { 99 // never called 100 if (! pThis) 101 CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything("xxx"); // address something 102 103 if ( nStack ) 104 { 105 // m68k stack is either 2 or 4 bytes aligned, doesn't really matter as 106 // we deal in 4 byte units anyway 107 sal_uInt32 nStackBytes = nStack * sizeof(sal_uInt32); 108 sal_uInt32 *stack = (sal_uInt32 *) __builtin_alloca( nStackBytes ); 109 memcpy( stack, pStack, nStackBytes ); 110 } 111 112 #ifdef CMC_DEBUG 113 // Let's figure out what is really going on here 114 { 115 fprintf( stderr, "\nStack (%d): ", nStack ); 116 for ( unsigned int i = 0; i < nStack; ++i ) 117 fprintf( stderr, "0x%lx, ", pStack[i] ); 118 fprintf( stderr, "\n" ); 119 fprintf( stderr, "pRegisterReturn is %p\n", pRegisterReturn); 120 } 121 #endif 122 123 sal_uInt32 pMethod = *((sal_uInt32*)pThis); 124 pMethod += 4 * nVtableIndex; 125 pMethod = *((sal_uInt32 *)pMethod); 126 127 typedef long (*FunctionCall )(); 128 FunctionCall pFunc = (FunctionCall)pMethod; 129 130 //stick the return area into r8 for big struct returning 131 asm volatile("movel %0,%%a1" : : "m"(pRegisterReturn) : ); 132 133 long d0 = (*pFunc)(); 134 135 register long d1 asm("d1"); 136 137 MapReturn(d0, d1, eReturnType, (long*)pRegisterReturn); 138 } 139 } 140 141 #define INSERT_INT32( pSV, pDS )\ 142 *pDS++ = *reinterpret_cast<sal_uInt32 *>( pSV ); 143 144 #define INSERT_INT64( pSV, pDS )\ 145 INSERT_INT32( pSV, pDS ) \ 146 INSERT_INT32( ((sal_uInt32*)pSV)+1, pDS ) 147 148 #define INSERT_FLOAT( pSV, pDS ) \ 149 INSERT_INT32( pSV, pDS ) 150 151 #define INSERT_DOUBLE( pSV, pDS ) \ 152 INSERT_INT64( pSV, pDS ) 153 154 #define INSERT_INT16( pSV, pDS ) \ 155 *pDS++ = *reinterpret_cast<sal_uInt16 *>( pSV ); 156 157 #define INSERT_INT8( pSV, pDS ) \ 158 *pDS++ = *reinterpret_cast<sal_uInt8 *>( pSV ); 159 160 namespace { 161 //======================================================================= 162 static void cpp_call( 163 bridges::cpp_uno::shared::UnoInterfaceProxy * pThis, 164 bridges::cpp_uno::shared::VtableSlot aVtableSlot, 165 typelib_TypeDescriptionReference * pReturnTypeRef, 166 sal_Int32 nParams, typelib_MethodParameter * pParams, 167 void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc ) 168 { 169 170 // max space for: [complex ret ptr], values|ptr ... 171 sal_uInt32 * pStack = (sal_uInt32 *)__builtin_alloca( 172 sizeof(sal_Int32) + ((nParams+2) * sizeof(sal_Int64)) ); 173 sal_uInt32 * pStackStart = pStack; 174 175 // return 176 typelib_TypeDescription * pReturnTypeDescr = 0; 177 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef ); 178 OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" ); 179 180 void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion 181 182 if (pReturnTypeDescr) 183 { 184 185 if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr )) 186 { 187 pCppReturn = pUnoReturn; // direct way for simple types 188 } 189 else 190 { 191 // complex return via ptr 192 pCppReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr ) 193 ? __builtin_alloca( pReturnTypeDescr->nSize ) 194 : pUnoReturn); // direct way 195 196 // INSERT_INT32( &pCppReturn, pStack ); 197 } 198 } 199 // push this 200 void * pAdjustedThisPtr = reinterpret_cast< void ** >(pThis->getCppI()) 201 + aVtableSlot.offset; 202 INSERT_INT32( &pAdjustedThisPtr, pStack ); 203 204 // stack space 205 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" ); 206 // args 207 void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams ); 208 // indizes of values this have to be converted (interface conversion cpp<=>uno) 209 sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams); 210 // type descriptions for reconversions 211 typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams)); 212 213 sal_Int32 nTempIndizes = 0; 214 215 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) 216 { 217 const typelib_MethodParameter & rParam = pParams[nPos]; 218 typelib_TypeDescription * pParamTypeDescr = 0; 219 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef ); 220 221 if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr )) 222 { 223 // uno_copyAndConvertData( pCppArgs[nPos] = pStack, pUnoArgs[nPos], 224 uno_copyAndConvertData( pCppArgs[nPos] = alloca(8), pUnoArgs[nPos], 225 pParamTypeDescr, pThis->getBridge()->getUno2Cpp() ); 226 227 switch (pParamTypeDescr->eTypeClass) 228 { 229 case typelib_TypeClass_HYPER: 230 case typelib_TypeClass_UNSIGNED_HYPER: 231 #ifdef CMC_DEBUG 232 fprintf(stderr, "hyper is %lx\n", pCppArgs[nPos]); 233 #endif 234 INSERT_INT64( pCppArgs[nPos], pStack ); 235 break; 236 case typelib_TypeClass_LONG: 237 case typelib_TypeClass_UNSIGNED_LONG: 238 case typelib_TypeClass_ENUM: 239 #ifdef CMC_DEBUG 240 fprintf(stderr, "long is %x\n", pCppArgs[nPos]); 241 #endif 242 INSERT_INT32( pCppArgs[nPos], pStack ); 243 break; 244 case typelib_TypeClass_SHORT: 245 case typelib_TypeClass_CHAR: 246 case typelib_TypeClass_UNSIGNED_SHORT: 247 INSERT_INT16( pCppArgs[nPos], pStack ); 248 break; 249 case typelib_TypeClass_BOOLEAN: 250 case typelib_TypeClass_BYTE: 251 INSERT_INT8( pCppArgs[nPos], pStack ); 252 break; 253 case typelib_TypeClass_FLOAT: 254 INSERT_FLOAT( pCppArgs[nPos], pStack ); 255 break; 256 case typelib_TypeClass_DOUBLE: 257 INSERT_DOUBLE( pCppArgs[nPos], pStack ); 258 break; 259 } 260 // no longer needed 261 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 262 } 263 else // ptr to complex value | ref 264 { 265 if (! rParam.bIn) // is pure out 266 { 267 // cpp out is constructed mem, uno out is not! 268 uno_constructData( 269 pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ), 270 pParamTypeDescr ); 271 pTempIndizes[nTempIndizes] = nPos; // default constructed for cpp call 272 // will be released at reconversion 273 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 274 } 275 // is in/inout 276 else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr )) 277 { 278 uno_copyAndConvertData( 279 pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ), 280 pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() ); 281 282 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted 283 // will be released at reconversion 284 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr; 285 } 286 else // direct way 287 { 288 pCppArgs[nPos] = pUnoArgs[nPos]; 289 // no longer needed 290 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 291 } 292 INSERT_INT32( &(pCppArgs[nPos]), pStack ); 293 } 294 } 295 296 try 297 { 298 callVirtualMethod( 299 pAdjustedThisPtr, aVtableSlot.index, 300 pCppReturn, pReturnTypeDescr->eTypeClass, 301 pStackStart, 302 (pStack - pStackStart)); 303 304 // NO exception occured... 305 *ppUnoExc = 0; 306 307 // reconvert temporary params 308 for ( ; nTempIndizes--; ) 309 { 310 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 311 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes]; 312 313 if (pParams[nIndex].bIn) 314 { 315 if (pParams[nIndex].bOut) // inout 316 { 317 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value 318 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr, 319 pThis->getBridge()->getCpp2Uno() ); 320 } 321 } 322 else // pure out 323 { 324 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr, 325 pThis->getBridge()->getCpp2Uno() ); 326 } 327 // destroy temp cpp param => cpp: every param was constructed 328 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release ); 329 330 TYPELIB_DANGER_RELEASE( pParamTypeDescr ); 331 } 332 // return value 333 if (pCppReturn && pUnoReturn != pCppReturn) 334 { 335 uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr, 336 pThis->getBridge()->getCpp2Uno() ); 337 uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release ); 338 } 339 } 340 catch (...) 341 { 342 // fill uno exception 343 fillUnoException( CPPU_CURRENT_NAMESPACE::__cxa_get_globals()->caughtExceptions, *ppUnoExc, pThis->getBridge()->getCpp2Uno() ); 344 345 // temporary params 346 for ( ; nTempIndizes--; ) 347 { 348 sal_Int32 nIndex = pTempIndizes[nTempIndizes]; 349 // destroy temp cpp param => cpp: every param was constructed 350 uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], cpp_release ); 351 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] ); 352 } 353 354 // return type 355 if (pReturnTypeDescr) 356 TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); 357 } 358 } 359 } 360 361 namespace bridges { namespace cpp_uno { namespace shared { 362 363 void unoInterfaceProxyDispatch( 364 uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr, 365 void * pReturn, void * pArgs[], uno_Any ** ppException ) 366 { 367 // is my surrogate 368 bridges::cpp_uno::shared::UnoInterfaceProxy * pThis 369 = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI); 370 typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr; 371 372 switch (pMemberDescr->eTypeClass) 373 { 374 case typelib_TypeClass_INTERFACE_ATTRIBUTE: 375 { 376 // determine vtable call index 377 sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition; 378 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### member pos out of range!" ); 379 380 VtableSlot aVtableSlot( 381 getVtableSlot( 382 reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *> 383 (pMemberDescr))); 384 385 if (pReturn) 386 { 387 // dependent dispatch 388 cpp_call( 389 pThis, aVtableSlot, 390 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef, 391 0, 0, // no params 392 pReturn, pArgs, ppException ); 393 } 394 else 395 { 396 // is SET 397 typelib_MethodParameter aParam; 398 aParam.pTypeRef = 399 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef; 400 aParam.bIn = sal_True; 401 aParam.bOut = sal_False; 402 403 typelib_TypeDescriptionReference * pReturnTypeRef = 0; 404 OUString aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") ); 405 typelib_typedescriptionreference_new( 406 &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData ); 407 408 // dependent dispatch 409 aVtableSlot.index += 1; 410 cpp_call( 411 pThis, aVtableSlot, // get, then set method 412 pReturnTypeRef, 413 1, &aParam, 414 pReturn, pArgs, ppException ); 415 416 typelib_typedescriptionreference_release( pReturnTypeRef ); 417 } 418 419 break; 420 } 421 case typelib_TypeClass_INTERFACE_METHOD: 422 { 423 // determine vtable call index 424 sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition; 425 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### member pos out of range!" ); 426 427 VtableSlot aVtableSlot( 428 getVtableSlot( 429 reinterpret_cast<typelib_InterfaceMethodTypeDescription const *> 430 (pMemberDescr))); 431 432 switch (aVtableSlot.index) 433 { 434 // standard calls 435 case 1: // acquire uno interface 436 (*pUnoI->acquire)( pUnoI ); 437 *ppException = 0; 438 break; 439 case 2: // release uno interface 440 (*pUnoI->release)( pUnoI ); 441 *ppException = 0; 442 break; 443 case 0: // queryInterface() opt 444 { 445 typelib_TypeDescription * pTD = 0; 446 TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() ); 447 if (pTD) 448 { 449 uno_Interface * pInterface = 0; 450 (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)( 451 pThis->getBridge()->getUnoEnv(), 452 (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD ); 453 454 if (pInterface) 455 { 456 ::uno_any_construct( 457 reinterpret_cast< uno_Any * >( pReturn ), 458 &pInterface, pTD, 0 ); 459 (*pInterface->release)( pInterface ); 460 TYPELIB_DANGER_RELEASE( pTD ); 461 *ppException = 0; 462 break; 463 } 464 TYPELIB_DANGER_RELEASE( pTD ); 465 } 466 } // else perform queryInterface() 467 default: 468 // dependent dispatch 469 cpp_call( 470 pThis, aVtableSlot, 471 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef, 472 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams, 473 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams, 474 pReturn, pArgs, ppException ); 475 } 476 break; 477 } 478 default: 479 { 480 ::com::sun::star::uno::RuntimeException aExc( 481 OUString( RTL_CONSTASCII_USTRINGPARAM("illegal member type description!") ), 482 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() ); 483 484 Type const & rExcType = ::getCppuType( &aExc ); 485 // binary identical null reference 486 ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 ); 487 } 488 } 489 } 490 491 } } } 492 493 /* vi:set tabstop=4 shiftwidth=4 expandtab: */ 494