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