merge the formfield patch from ooo-build
[ooovba.git] / bridges / source / cpp_uno / gcc3_linux_x86-64 / uno2cpp.cxx
blob9f97c5adf786d47a6260820896efed3aa0c02ad8
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: uno2cpp.cxx,v $
10 * $Revision: 1.10 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_bridges.hxx"
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <rtl/alloc.h>
39 #include <com/sun/star/uno/genfunc.hxx>
40 #include "com/sun/star/uno/RuntimeException.hpp"
41 #include <uno/data.h>
43 #include <bridges/cpp_uno/shared/bridge.hxx>
44 #include <bridges/cpp_uno/shared/types.hxx>
45 #include "bridges/cpp_uno/shared/unointerfaceproxy.hxx"
46 #include "bridges/cpp_uno/shared/vtables.hxx"
48 #include "abi.hxx"
49 #include "share.hxx"
51 using namespace ::rtl;
52 using namespace ::com::sun::star::uno;
54 //==================================================================================================
55 static void callVirtualMethod(void * pThis, sal_uInt32 nVtableIndex,
56 void * pRegisterReturn, typelib_TypeDescription * pReturnTypeDescr, bool bSimpleReturn,
57 sal_uInt64 *pStack, sal_uInt32 nStack,
58 sal_uInt64 *pGPR, sal_uInt32 nGPR,
59 double *pFPR, sal_uInt32 nFPR) __attribute__((noinline));
61 static void callVirtualMethod(void * pThis, sal_uInt32 nVtableIndex,
62 void * pRegisterReturn, typelib_TypeDescription * pReturnTypeDescr, bool bSimpleReturn,
63 sal_uInt64 *pStack, sal_uInt32 nStack,
64 sal_uInt64 *pGPR, sal_uInt32 nGPR,
65 double *pFPR, sal_uInt32 nFPR)
67 #if OSL_DEBUG_LEVEL > 1
68 // Let's figure out what is really going on here
70 fprintf( stderr, "= callVirtualMethod() =\nGPR's (%d): ", nGPR );
71 for ( unsigned int i = 0; i < nGPR; ++i )
72 fprintf( stderr, "0x%lx, ", pGPR[i] );
73 fprintf( stderr, "\nFPR's (%d): ", nFPR );
74 for ( unsigned int i = 0; i < nFPR; ++i )
75 fprintf( stderr, "%f, ", pFPR[i] );
76 fprintf( stderr, "\nStack (%d): ", nStack );
77 for ( unsigned int i = 0; i < nStack; ++i )
78 fprintf( stderr, "0x%lx, ", pStack[i] );
79 fprintf( stderr, "\n" );
81 #endif
83 // The call instruction within the asm section of callVirtualMethod may throw
84 // exceptions. So that the compiler handles this correctly, it is important
85 // that (a) callVirtualMethod might call dummy_can_throw_anything (although this
86 // never happens at runtime), which in turn can throw exceptions, and (b)
87 // callVirtualMethod is not inlined at its call site (so that any exceptions are
88 // caught which are thrown from the instruction calling callVirtualMethod):
89 if ( !pThis )
90 CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything( "xxx" ); // address something
92 // Should not happen, but...
93 if ( nFPR > x86_64::MAX_SSE_REGS )
94 nFPR = x86_64::MAX_SSE_REGS;
95 if ( nGPR > x86_64::MAX_GPR_REGS )
96 nGPR = x86_64::MAX_GPR_REGS;
98 // Get pointer to method
99 sal_uInt64 pMethod = *((sal_uInt64 *)pThis);
100 pMethod += 8 * nVtableIndex;
101 pMethod = *((sal_uInt64 *)pMethod);
103 // Load parameters to stack, if necessary
104 if ( nStack )
106 // 16-bytes aligned
107 sal_uInt32 nStackBytes = ( ( nStack + 1 ) >> 1 ) * 16;
108 sal_uInt64 *pCallStack = (sal_uInt64 *) __builtin_alloca( nStackBytes );
109 memcpy( pCallStack, pStack, nStackBytes );
112 // Return values
113 sal_uInt64 rax;
114 sal_uInt64 rdx;
115 double xmm0;
117 asm volatile (
119 // Fill the xmm registers
120 "movq %2, %%rax\n\t"
122 "movsd (%%rax), %%xmm0\n\t"
123 "movsd 8(%%rax), %%xmm1\n\t"
124 "movsd 16(%%rax), %%xmm2\n\t"
125 "movsd 24(%%rax), %%xmm3\n\t"
126 "movsd 32(%%rax), %%xmm4\n\t"
127 "movsd 40(%%rax), %%xmm5\n\t"
128 "movsd 48(%%rax), %%xmm6\n\t"
129 "movsd 56(%%rax), %%xmm7\n\t"
131 // Fill the general purpose registers
132 "movq %1, %%rax\n\t"
134 "movq (%%rax), %%rdi\n\t"
135 "movq 8(%%rax), %%rsi\n\t"
136 "movq 16(%%rax), %%rdx\n\t"
137 "movq 24(%%rax), %%rcx\n\t"
138 "movq 32(%%rax), %%r8\n\t"
139 "movq 40(%%rax), %%r9\n\t"
141 // Perform the call
142 "movq %0, %%r11\n\t"
143 "movq %3, %%rax\n\t"
144 "call *%%r11\n\t"
146 // Fill the return values
147 "movq %%rax, %4\n\t"
148 "movq %%rdx, %5\n\t"
149 "movsd %%xmm0, %6\n\t"
151 : "m" ( pMethod ), "m" ( pGPR ), "m" ( pFPR ), "m" ( nFPR ),
152 "m" ( rax ), "m" ( rdx ), "m" ( xmm0 )
153 : "rax", "rdi", "rsi", "rdx", "rcx", "r8", "r9", "r11"
156 switch (pReturnTypeDescr->eTypeClass)
158 case typelib_TypeClass_HYPER:
159 case typelib_TypeClass_UNSIGNED_HYPER:
160 *reinterpret_cast<sal_uInt64 *>( pRegisterReturn ) = rax;
161 break;
162 case typelib_TypeClass_LONG:
163 case typelib_TypeClass_UNSIGNED_LONG:
164 case typelib_TypeClass_ENUM:
165 *reinterpret_cast<sal_uInt32 *>( pRegisterReturn ) = *reinterpret_cast<sal_uInt32*>( &rax );
166 break;
167 case typelib_TypeClass_CHAR:
168 case typelib_TypeClass_SHORT:
169 case typelib_TypeClass_UNSIGNED_SHORT:
170 *reinterpret_cast<sal_uInt16 *>( pRegisterReturn ) = *reinterpret_cast<sal_uInt16*>( &rax );
171 break;
172 case typelib_TypeClass_BOOLEAN:
173 case typelib_TypeClass_BYTE:
174 *reinterpret_cast<sal_uInt8 *>( pRegisterReturn ) = *reinterpret_cast<sal_uInt8*>( &rax );
175 break;
176 case typelib_TypeClass_FLOAT:
177 case typelib_TypeClass_DOUBLE:
178 *reinterpret_cast<double *>( pRegisterReturn ) = xmm0;
179 break;
180 default:
182 sal_Int32 const nRetSize = pReturnTypeDescr->nSize;
183 if (bSimpleReturn && nRetSize <= 16 && nRetSize > 0)
185 if (nRetSize > 8)
186 static_cast<sal_uInt64 *>(pRegisterReturn)[1] = rdx;
187 static_cast<sal_uInt64 *>(pRegisterReturn)[0] = rax;
189 break;
194 //==================================================================================================
196 // Macros for easier insertion of values to registers or stack
197 // pSV - pointer to the source
198 // nr - order of the value [will be increased if stored to register]
199 // pFPR, pGPR - pointer to the registers
200 // pDS - pointer to the stack [will be increased if stored here]
202 // The value in %xmm register is already prepared to be retrieved as a float,
203 // thus we treat float and double the same
204 #define INSERT_FLOAT_DOUBLE( pSV, nr, pFPR, pDS ) \
205 if ( nr < x86_64::MAX_SSE_REGS ) \
206 pFPR[nr++] = *reinterpret_cast<double *>( pSV ); \
207 else \
208 *pDS++ = *reinterpret_cast<sal_uInt64 *>( pSV ); // verbatim!
210 #define INSERT_INT64( pSV, nr, pGPR, pDS ) \
211 if ( nr < x86_64::MAX_GPR_REGS ) \
212 pGPR[nr++] = *reinterpret_cast<sal_uInt64 *>( pSV ); \
213 else \
214 *pDS++ = *reinterpret_cast<sal_uInt64 *>( pSV );
216 #define INSERT_INT32( pSV, nr, pGPR, pDS ) \
217 if ( nr < x86_64::MAX_GPR_REGS ) \
218 pGPR[nr++] = *reinterpret_cast<sal_uInt32 *>( pSV ); \
219 else \
220 *pDS++ = *reinterpret_cast<sal_uInt32 *>( pSV );
222 #define INSERT_INT16( pSV, nr, pGPR, pDS ) \
223 if ( nr < x86_64::MAX_GPR_REGS ) \
224 pGPR[nr++] = *reinterpret_cast<sal_uInt16 *>( pSV ); \
225 else \
226 *pDS++ = *reinterpret_cast<sal_uInt16 *>( pSV );
228 #define INSERT_INT8( pSV, nr, pGPR, pDS ) \
229 if ( nr < x86_64::MAX_GPR_REGS ) \
230 pGPR[nr++] = *reinterpret_cast<sal_uInt8 *>( pSV ); \
231 else \
232 *pDS++ = *reinterpret_cast<sal_uInt8 *>( pSV );
234 //==================================================================================================
236 static void cpp_call(
237 bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
238 bridges::cpp_uno::shared::VtableSlot aVtableSlot,
239 typelib_TypeDescriptionReference * pReturnTypeRef,
240 sal_Int32 nParams, typelib_MethodParameter * pParams,
241 void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
243 // Maxium space for [complex ret ptr], values | ptr ...
244 // (but will be used less - some of the values will be in pGPR and pFPR)
245 sal_uInt64 *pStack = (sal_uInt64 *)__builtin_alloca( (nParams + 3) * sizeof(sal_uInt64) );
246 sal_uInt64 *pStackStart = pStack;
248 sal_uInt64 pGPR[x86_64::MAX_GPR_REGS];
249 sal_uInt32 nGPR = 0;
251 double pFPR[x86_64::MAX_SSE_REGS];
252 sal_uInt32 nFPR = 0;
254 // Return
255 typelib_TypeDescription * pReturnTypeDescr = 0;
256 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
257 OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" );
259 void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion (see below)
261 bool bSimpleReturn = true;
262 if ( pReturnTypeDescr )
264 if ( x86_64::return_in_hidden_param( pReturnTypeRef ) )
265 bSimpleReturn = false;
267 if ( bSimpleReturn )
268 pCppReturn = pUnoReturn; // direct way for simple types
269 else
271 // complex return via ptr
272 pCppReturn = bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )?
273 __builtin_alloca( pReturnTypeDescr->nSize ) : pUnoReturn;
274 INSERT_INT64( &pCppReturn, nGPR, pGPR, pStack );
278 // Push "this" pointer
279 void * pAdjustedThisPtr = reinterpret_cast< void ** >( pThis->getCppI() ) + aVtableSlot.offset;
280 INSERT_INT64( &pAdjustedThisPtr, nGPR, pGPR, pStack );
282 // Args
283 void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams );
284 // Indizes of values this have to be converted (interface conversion cpp<=>uno)
285 sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams);
286 // Type descriptions for reconversions
287 typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
289 sal_Int32 nTempIndizes = 0;
291 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
293 const typelib_MethodParameter & rParam = pParams[nPos];
294 typelib_TypeDescription * pParamTypeDescr = 0;
295 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
297 if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
299 uno_copyAndConvertData( pCppArgs[nPos] = alloca( 8 ), pUnoArgs[nPos], pParamTypeDescr,
300 pThis->getBridge()->getUno2Cpp() );
302 switch (pParamTypeDescr->eTypeClass)
304 case typelib_TypeClass_HYPER:
305 case typelib_TypeClass_UNSIGNED_HYPER:
306 INSERT_INT64( pCppArgs[nPos], nGPR, pGPR, pStack );
307 break;
308 case typelib_TypeClass_LONG:
309 case typelib_TypeClass_UNSIGNED_LONG:
310 case typelib_TypeClass_ENUM:
311 INSERT_INT32( pCppArgs[nPos], nGPR, pGPR, pStack );
312 break;
313 case typelib_TypeClass_SHORT:
314 case typelib_TypeClass_CHAR:
315 case typelib_TypeClass_UNSIGNED_SHORT:
316 INSERT_INT16( pCppArgs[nPos], nGPR, pGPR, pStack );
317 break;
318 case typelib_TypeClass_BOOLEAN:
319 case typelib_TypeClass_BYTE:
320 INSERT_INT8( pCppArgs[nPos], nGPR, pGPR, pStack );
321 break;
322 case typelib_TypeClass_FLOAT:
323 case typelib_TypeClass_DOUBLE:
324 INSERT_FLOAT_DOUBLE( pCppArgs[nPos], nFPR, pFPR, pStack );
325 break;
326 default:
327 break;
330 // no longer needed
331 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
333 else // ptr to complex value | ref
335 if (! rParam.bIn) // is pure out
337 // cpp out is constructed mem, uno out is not!
338 uno_constructData(
339 pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
340 pParamTypeDescr );
341 pTempIndizes[nTempIndizes] = nPos; // default constructed for cpp call
342 // will be released at reconversion
343 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
345 // is in/inout
346 else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
348 uno_copyAndConvertData(
349 pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
350 pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
352 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
353 // will be released at reconversion
354 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
356 else // direct way
358 pCppArgs[nPos] = pUnoArgs[nPos];
359 // no longer needed
360 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
362 INSERT_INT64( &(pCppArgs[nPos]), nGPR, pGPR, pStack );
368 callVirtualMethod(
369 pAdjustedThisPtr, aVtableSlot.index,
370 pCppReturn, pReturnTypeDescr, bSimpleReturn,
371 pStackStart, ( pStack - pStackStart ),
372 pGPR, nGPR,
373 pFPR, nFPR );
374 // NO exception occured...
375 *ppUnoExc = 0;
377 // reconvert temporary params
378 for ( ; nTempIndizes--; )
380 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
381 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
383 if (pParams[nIndex].bIn)
385 if (pParams[nIndex].bOut) // inout
387 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
388 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
389 pThis->getBridge()->getCpp2Uno() );
392 else // pure out
394 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
395 pThis->getBridge()->getCpp2Uno() );
397 // destroy temp cpp param => cpp: every param was constructed
398 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
400 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
402 // return value
403 if (pCppReturn && pUnoReturn != pCppReturn)
405 uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
406 pThis->getBridge()->getCpp2Uno() );
407 uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
410 catch (...)
412 // fill uno exception
413 fillUnoException( CPPU_CURRENT_NAMESPACE::__cxa_get_globals()->caughtExceptions, *ppUnoExc, pThis->getBridge()->getCpp2Uno() );
415 // temporary params
416 for ( ; nTempIndizes--; )
418 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
419 // destroy temp cpp param => cpp: every param was constructed
420 uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], cpp_release );
421 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
423 // return type
424 if (pReturnTypeDescr)
425 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
429 //==================================================================================================
431 namespace bridges { namespace cpp_uno { namespace shared {
433 void unoInterfaceProxyDispatch(
434 uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
435 void * pReturn, void * pArgs[], uno_Any ** ppException )
437 // is my surrogate
438 bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
439 = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
440 #if OSL_DEBUG_LEVEL > 0
441 typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
442 #endif
444 switch (pMemberDescr->eTypeClass)
446 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
448 #if OSL_DEBUG_LEVEL > 0
449 // determine vtable call index
450 sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition;
451 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### member pos out of range!" );
452 #endif
453 VtableSlot aVtableSlot(
454 getVtableSlot(
455 reinterpret_cast<
456 typelib_InterfaceAttributeTypeDescription const * >(
457 pMemberDescr)));
459 if (pReturn)
461 // dependent dispatch
462 cpp_call(
463 pThis, aVtableSlot,
464 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
465 0, 0, // no params
466 pReturn, pArgs, ppException );
468 else
470 // is SET
471 typelib_MethodParameter aParam;
472 aParam.pTypeRef =
473 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
474 aParam.bIn = sal_True;
475 aParam.bOut = sal_False;
477 typelib_TypeDescriptionReference * pReturnTypeRef = 0;
478 OUString aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") );
479 typelib_typedescriptionreference_new(
480 &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
482 // dependent dispatch
483 aVtableSlot.index += 1; // get, then set method
484 cpp_call(
485 pThis, aVtableSlot, // get, then set method
486 pReturnTypeRef,
487 1, &aParam,
488 pReturn, pArgs, ppException );
490 typelib_typedescriptionreference_release( pReturnTypeRef );
493 break;
495 case typelib_TypeClass_INTERFACE_METHOD:
497 #if OSL_DEBUG_LEVEL > 0
498 // determine vtable call index
499 sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition;
500 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### member pos out of range!" );
501 #endif
502 VtableSlot aVtableSlot(
503 getVtableSlot(
504 reinterpret_cast<
505 typelib_InterfaceMethodTypeDescription const * >(
506 pMemberDescr)));
508 switch (aVtableSlot.index)
510 // standard calls
511 case 1: // acquire uno interface
512 (*pUnoI->acquire)( pUnoI );
513 *ppException = 0;
514 break;
515 case 2: // release uno interface
516 (*pUnoI->release)( pUnoI );
517 *ppException = 0;
518 break;
519 case 0: // queryInterface() opt
521 typelib_TypeDescription * pTD = 0;
522 TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() );
523 if (pTD)
525 uno_Interface * pInterface = 0;
526 (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)(
527 pThis->getBridge()->getUnoEnv(),
528 (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
530 if (pInterface)
532 ::uno_any_construct(
533 reinterpret_cast< uno_Any * >( pReturn ),
534 &pInterface, pTD, 0 );
535 (*pInterface->release)( pInterface );
536 TYPELIB_DANGER_RELEASE( pTD );
537 *ppException = 0;
538 break;
540 TYPELIB_DANGER_RELEASE( pTD );
542 } // else perform queryInterface()
543 default:
544 // dependent dispatch
545 cpp_call(
546 pThis, aVtableSlot,
547 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef,
548 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams,
549 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams,
550 pReturn, pArgs, ppException );
552 break;
554 default:
556 ::com::sun::star::uno::RuntimeException aExc(
557 OUString( RTL_CONSTASCII_USTRINGPARAM("illegal member type description!") ),
558 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
560 Type const & rExcType = ::getCppuType( &aExc );
561 // binary identical null reference
562 ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
567 } } }