merge the formfield patch from ooo-build
[ooovba.git] / bridges / source / cpp_uno / gcc3_linux_x86-64 / cpp2uno.cxx
blobce818ef3c44fbb624437020c07e4a6658f785961
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: cpp2uno.cxx,v $
10 * $Revision: 1.9 $
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 <hash_map>
38 #include <rtl/alloc.h>
39 #include <osl/mutex.hxx>
41 #include <com/sun/star/uno/genfunc.hxx>
42 #include "com/sun/star/uno/RuntimeException.hpp"
43 #include <uno/data.h>
44 #include <typelib/typedescription.hxx>
46 #include "bridges/cpp_uno/shared/bridge.hxx"
47 #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx"
48 #include "bridges/cpp_uno/shared/types.hxx"
49 #include "bridges/cpp_uno/shared/vtablefactory.hxx"
51 #include "abi.hxx"
52 #include "share.hxx"
54 using namespace ::osl;
55 using namespace ::rtl;
56 using namespace ::com::sun::star::uno;
58 //==================================================================================================
60 // Perform the UNO call
62 // We must convert the paramaters stored in gpreg, fpreg and ovrflw to UNO
63 // arguments and call pThis->getUnoI()->pDispatcher.
65 // gpreg: [ret *], this, [gpr params]
66 // fpreg: [fpr params]
67 // ovrflw: [gpr or fpr params (properly aligned)]
69 // [ret *] is present when we are returning a structure bigger than 16 bytes
70 // Simple types are returned in rax, rdx (int), or xmm0, xmm1 (fp).
71 // Similarly structures <= 16 bytes are in rax, rdx, xmm0, xmm1 as necessary.
72 static typelib_TypeClass cpp2uno_call(
73 bridges::cpp_uno::shared::CppInterfaceProxy * pThis,
74 const typelib_TypeDescription * pMemberTypeDescr,
75 typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return
76 sal_Int32 nParams, typelib_MethodParameter * pParams,
77 void ** gpreg, void ** fpreg, void ** ovrflw,
78 sal_uInt64 * pRegisterReturn /* space for register return */ )
80 unsigned int nr_gpr = 0; //number of gpr registers used
81 unsigned int nr_fpr = 0; //number of fpr registers used
83 // return
84 typelib_TypeDescription * pReturnTypeDescr = 0;
85 if (pReturnTypeRef)
86 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
88 void * pUnoReturn = 0;
89 void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
91 if ( pReturnTypeDescr )
93 if ( x86_64::return_in_hidden_param( pReturnTypeRef ) )
95 pCppReturn = *gpreg++;
96 nr_gpr++;
98 pUnoReturn = ( bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
99 ? alloca( pReturnTypeDescr->nSize )
100 : pCppReturn ); // direct way
102 else
103 pUnoReturn = pRegisterReturn; // direct way for simple types
106 // pop this
107 gpreg++;
108 nr_gpr++;
110 // stack space
111 // parameters
112 void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams );
113 void ** pCppArgs = pUnoArgs + nParams;
114 // indizes of values this have to be converted (interface conversion cpp<=>uno)
115 sal_Int32 * pTempIndizes = (sal_Int32 *)(pUnoArgs + (2 * nParams));
116 // type descriptions for reconversions
117 typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams));
119 sal_Int32 nTempIndizes = 0;
121 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
123 const typelib_MethodParameter & rParam = pParams[nPos];
124 typelib_TypeDescription * pParamTypeDescr = 0;
125 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
127 int nUsedGPR = 0;
128 int nUsedSSE = 0;
129 bool bFitsRegisters = x86_64::examine_argument( rParam.pTypeRef, false, nUsedGPR, nUsedSSE );
130 if ( !rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ) ) // value
132 // Simple types must fit exactly one register on x86_64
133 OSL_ASSERT( bFitsRegisters && ( ( nUsedSSE == 1 && nUsedGPR == 0 ) || ( nUsedSSE == 0 && nUsedGPR == 1 ) ) );
135 if ( nUsedSSE == 1 )
137 if ( nr_fpr < x86_64::MAX_SSE_REGS )
139 pCppArgs[nPos] = pUnoArgs[nPos] = fpreg++;
140 nr_fpr++;
142 else
143 pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw++;
145 else if ( nUsedGPR == 1 )
147 if ( nr_gpr < x86_64::MAX_GPR_REGS )
149 pCppArgs[nPos] = pUnoArgs[nPos] = gpreg++;
150 nr_gpr++;
152 else
153 pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw++;
156 // no longer needed
157 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
159 else // struct <= 16 bytes || ptr to complex value || ref
161 void *pCppStack;
162 char pTmpStruct[16];
164 if ( bFitsRegisters && !rParam.bOut &&
165 ( pParamTypeDescr->eTypeClass == typelib_TypeClass_STRUCT ||
166 pParamTypeDescr->eTypeClass == typelib_TypeClass_EXCEPTION ) )
168 if ( ( nr_gpr + nUsedGPR <= x86_64::MAX_GPR_REGS ) && ( nr_fpr + nUsedSSE <= x86_64::MAX_SSE_REGS ) )
170 x86_64::fill_struct( rParam.pTypeRef, gpreg, fpreg, pTmpStruct );
171 #if OSL_DEBUG_LEVEL > 1
172 fprintf( stderr, "nUsedGPR == %d, nUsedSSE == %d, pTmpStruct[0] == 0x%x, pTmpStruct[1] == 0x%x, **gpreg == 0x%lx\n",
173 nUsedGPR, nUsedSSE, pTmpStruct[0], pTmpStruct[1], *(sal_uInt64*)*gpreg );
174 #endif
176 pCppArgs[nPos] = pCppStack = reinterpret_cast<void *>( pTmpStruct );
177 gpreg += nUsedGPR;
178 fpreg += nUsedSSE;
180 else
181 pCppArgs[nPos] = pCppStack = *ovrflw++;
183 else if ( nr_gpr < x86_64::MAX_GPR_REGS )
185 pCppArgs[nPos] = pCppStack = *gpreg++;
186 nr_gpr++;
188 else
189 pCppArgs[nPos] = pCppStack = *ovrflw++;
191 if (! rParam.bIn) // is pure out
193 // uno out is unconstructed mem!
194 pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
195 pTempIndizes[nTempIndizes] = nPos;
196 // will be released at reconversion
197 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
199 else if ( bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ) ) // is in/inout
201 uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
202 pCppStack, pParamTypeDescr,
203 pThis->getBridge()->getCpp2Uno() );
204 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
205 // will be released at reconversion
206 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
208 else // direct way
210 pUnoArgs[nPos] = pCppStack;
211 // no longer needed
212 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
217 // ExceptionHolder
218 uno_Any aUnoExc; // Any will be constructed by callee
219 uno_Any * pUnoExc = &aUnoExc;
221 // invoke uno dispatch call
222 (*pThis->getUnoI()->pDispatcher)( pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
224 // in case an exception occured...
225 if ( pUnoExc )
227 // destruct temporary in/inout params
228 for ( ; nTempIndizes--; )
230 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
232 if (pParams[nIndex].bIn) // is in/inout => was constructed
233 uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], 0 );
234 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
236 if (pReturnTypeDescr)
237 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
239 CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc, pThis->getBridge()->getUno2Cpp() ); // has to destruct the any
240 // is here for dummy
241 return typelib_TypeClass_VOID;
243 else // else no exception occured...
245 // temporary params
246 for ( ; nTempIndizes--; )
248 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
249 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
251 if ( pParams[nIndex].bOut ) // inout/out
253 // convert and assign
254 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
255 uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
256 pThis->getBridge()->getUno2Cpp() );
258 // destroy temp uno param
259 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
261 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
263 // return
264 if ( pCppReturn ) // has complex return
266 if ( pUnoReturn != pCppReturn ) // needs reconversion
268 uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
269 pThis->getBridge()->getUno2Cpp() );
270 // destroy temp uno return
271 uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
273 // complex return ptr is set to return reg
274 *(void **)pRegisterReturn = pCppReturn;
276 if ( pReturnTypeDescr )
278 typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
279 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
280 return eRet;
282 else
283 return typelib_TypeClass_VOID;
288 //==================================================================================================
289 extern "C" typelib_TypeClass cpp_vtable_call(
290 sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
291 void ** gpreg, void ** fpreg, void ** ovrflw,
292 sal_uInt64 * pRegisterReturn /* space for register return */ )
294 // gpreg: [ret *], this, [other gpr params]
295 // fpreg: [fpr params]
296 // ovrflw: [gpr or fpr params (properly aligned)]
297 void * pThis;
298 if ( nFunctionIndex & 0x80000000 )
300 nFunctionIndex &= 0x7fffffff;
301 pThis = gpreg[1];
303 else
305 pThis = gpreg[0];
307 pThis = static_cast<char *>( pThis ) - nVtableOffset;
309 bridges::cpp_uno::shared::CppInterfaceProxy * pCppI =
310 bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( pThis );
312 typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
314 OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!\n" );
315 if ( nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex )
317 throw RuntimeException( OUString::createFromAscii("illegal vtable index!"),
318 reinterpret_cast<XInterface *>( pCppI ) );
321 // determine called method
322 sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
323 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!\n" );
325 TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
327 typelib_TypeClass eRet;
328 switch ( aMemberDescr.get()->eTypeClass )
330 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
332 typelib_TypeDescriptionReference *pAttrTypeRef =
333 reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( aMemberDescr.get() )->pAttributeTypeRef;
335 if ( pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex )
337 // is GET method
338 eRet = cpp2uno_call( pCppI, aMemberDescr.get(), pAttrTypeRef,
339 0, 0, // no params
340 gpreg, fpreg, ovrflw, pRegisterReturn );
342 else
344 // is SET method
345 typelib_MethodParameter aParam;
346 aParam.pTypeRef = pAttrTypeRef;
347 aParam.bIn = sal_True;
348 aParam.bOut = sal_False;
350 eRet = cpp2uno_call( pCppI, aMemberDescr.get(),
351 0, // indicates void return
352 1, &aParam,
353 gpreg, fpreg, ovrflw, pRegisterReturn );
355 break;
357 case typelib_TypeClass_INTERFACE_METHOD:
359 // is METHOD
360 switch ( nFunctionIndex )
362 case 1: // acquire()
363 pCppI->acquireProxy(); // non virtual call!
364 eRet = typelib_TypeClass_VOID;
365 break;
366 case 2: // release()
367 pCppI->releaseProxy(); // non virtual call!
368 eRet = typelib_TypeClass_VOID;
369 break;
370 case 0: // queryInterface() opt
372 typelib_TypeDescription * pTD = 0;
373 TYPELIB_DANGER_GET( &pTD, reinterpret_cast<Type *>( gpreg[2] )->getTypeLibType() );
374 if ( pTD )
376 XInterface * pInterface = 0;
377 (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)
378 ( pCppI->getBridge()->getCppEnv(),
379 (void **)&pInterface,
380 pCppI->getOid().pData,
381 reinterpret_cast<typelib_InterfaceTypeDescription *>( pTD ) );
383 if ( pInterface )
385 ::uno_any_construct( reinterpret_cast<uno_Any *>( gpreg[0] ),
386 &pInterface, pTD, cpp_acquire );
388 pInterface->release();
389 TYPELIB_DANGER_RELEASE( pTD );
391 reinterpret_cast<void **>( pRegisterReturn )[0] = gpreg[0];
392 eRet = typelib_TypeClass_ANY;
393 break;
395 TYPELIB_DANGER_RELEASE( pTD );
397 } // else perform queryInterface()
398 default:
400 typelib_InterfaceMethodTypeDescription *pMethodTD =
401 reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( aMemberDescr.get() );
403 eRet = cpp2uno_call( pCppI, aMemberDescr.get(),
404 pMethodTD->pReturnTypeRef,
405 pMethodTD->nParams,
406 pMethodTD->pParams,
407 gpreg, fpreg, ovrflw, pRegisterReturn );
410 break;
412 default:
414 throw RuntimeException( OUString::createFromAscii("no member description found!"),
415 reinterpret_cast<XInterface *>( pCppI ) );
416 // is here for dummy
417 eRet = typelib_TypeClass_VOID;
421 return eRet;
424 //==================================================================================================
425 extern "C" void privateSnippetExecutor( ... );
427 const int codeSnippetSize = 24;
429 // Generate a trampoline that redirects method calls to
430 // privateSnippetExecutor().
432 // privateSnippetExecutor() saves all the registers that are used for
433 // parameter passing on x86_64, and calls the cpp_vtable_call().
434 // When it returns, privateSnippetExecutor() sets the return value.
436 // Note: The code snippet we build here must not create a stack frame,
437 // otherwise the UNO exceptions stop working thanks to non-existing
438 // unwinding info.
439 unsigned char * codeSnippet( unsigned char * code,
440 sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
441 bool bHasHiddenParam ) SAL_THROW( () )
443 sal_uInt64 nOffsetAndIndex = ( ( (sal_uInt64) nVtableOffset ) << 32 ) | ( (sal_uInt64) nFunctionIndex );
445 if ( bHasHiddenParam )
446 nOffsetAndIndex |= 0x80000000;
448 // movq $<nOffsetAndIndex>, %r10
449 *reinterpret_cast<sal_uInt16 *>( code ) = 0xba49;
450 *reinterpret_cast<sal_uInt64 *>( code + 2 ) = nOffsetAndIndex;
452 // movq $<address of the privateSnippetExecutor>, %r11
453 *reinterpret_cast<sal_uInt16 *>( code + 10 ) = 0xbb49;
454 *reinterpret_cast<sal_uInt64 *>( code + 12 ) = reinterpret_cast<sal_uInt64>( privateSnippetExecutor );
456 // jmpq *%r11
457 *reinterpret_cast<sal_uInt32 *>( code + 20 ) = 0x00e3ff49;
459 return code + codeSnippetSize;
462 //==================================================================================================
463 struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; };
465 bridges::cpp_uno::shared::VtableFactory::Slot *
466 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
468 return static_cast< Slot * >(block) + 2;
471 //==================================================================================================
472 sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize(
473 sal_Int32 slotCount)
475 return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
478 //==================================================================================================
479 bridges::cpp_uno::shared::VtableFactory::Slot *
480 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
481 void * block, sal_Int32 slotCount)
483 Slot * slots = mapBlockToVtable(block);
484 slots[-2].fn = 0;
485 slots[-1].fn = 0;
486 return slots + slotCount;
489 //==================================================================================================
491 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
492 Slot ** slots, unsigned char * code, sal_PtrDiff writetoexecdiff,
493 typelib_InterfaceTypeDescription const * type, sal_Int32 nFunctionOffset,
494 sal_Int32 functionCount, sal_Int32 nVtableOffset )
496 (*slots) -= functionCount;
497 Slot * s = *slots;
498 for ( sal_Int32 nPos = 0; nPos < type->nMembers; ++nPos )
500 typelib_TypeDescription * pTD = 0;
502 TYPELIB_DANGER_GET( &pTD, type->ppMembers[ nPos ] );
503 OSL_ASSERT( pTD );
505 if ( typelib_TypeClass_INTERFACE_ATTRIBUTE == pTD->eTypeClass )
507 typelib_InterfaceAttributeTypeDescription *pAttrTD =
508 reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( pTD );
510 // get method
511 (s++)->fn = code + writetoexecdiff;
512 code = codeSnippet( code, nFunctionOffset++, nVtableOffset,
513 x86_64::return_in_hidden_param( pAttrTD->pAttributeTypeRef ) );
515 if ( ! pAttrTD->bReadOnly )
517 // set method
518 (s++)->fn = code + writetoexecdiff;
519 code = codeSnippet( code, nFunctionOffset++, nVtableOffset, false );
522 else if ( typelib_TypeClass_INTERFACE_METHOD == pTD->eTypeClass )
524 typelib_InterfaceMethodTypeDescription *pMethodTD =
525 reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( pTD );
527 (s++)->fn = code + writetoexecdiff;
528 code = codeSnippet( code, nFunctionOffset++, nVtableOffset,
529 x86_64::return_in_hidden_param( pMethodTD->pReturnTypeRef ) );
531 else
532 OSL_ASSERT( false );
534 TYPELIB_DANGER_RELEASE( pTD );
536 return code;
539 //==================================================================================================
540 void bridges::cpp_uno::shared::VtableFactory::flushCode(
541 unsigned char const *, unsigned char const * )