1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: cpp2uno.cxx,v $
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"
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"
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"
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
84 typelib_TypeDescription
* pReturnTypeDescr
= 0;
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
++;
98 pUnoReturn
= ( bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr
)
99 ? alloca( pReturnTypeDescr
->nSize
)
100 : pCppReturn
); // direct way
103 pUnoReturn
= pRegisterReturn
; // direct way for simple types
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
);
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 ) ) );
137 if ( nr_fpr
< x86_64::MAX_SSE_REGS
)
139 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = fpreg
++;
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
++;
153 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = ovrflw
++;
157 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
159 else // struct <= 16 bytes || ptr to complex value || ref
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
);
176 pCppArgs
[nPos
] = pCppStack
= reinterpret_cast<void *>( pTmpStruct
);
181 pCppArgs
[nPos
] = pCppStack
= *ovrflw
++;
183 else if ( nr_gpr
< x86_64::MAX_GPR_REGS
)
185 pCppArgs
[nPos
] = pCppStack
= *gpreg
++;
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
;
210 pUnoArgs
[nPos
] = pCppStack
;
212 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
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...
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
241 return typelib_TypeClass_VOID
;
243 else // else no exception occured...
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
);
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
);
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)]
298 if ( nFunctionIndex
& 0x80000000 )
300 nFunctionIndex
&= 0x7fffffff;
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
)
338 eRet
= cpp2uno_call( pCppI
, aMemberDescr
.get(), pAttrTypeRef
,
340 gpreg
, fpreg
, ovrflw
, pRegisterReturn
);
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
353 gpreg
, fpreg
, ovrflw
, pRegisterReturn
);
357 case typelib_TypeClass_INTERFACE_METHOD
:
360 switch ( nFunctionIndex
)
363 pCppI
->acquireProxy(); // non virtual call!
364 eRet
= typelib_TypeClass_VOID
;
367 pCppI
->releaseProxy(); // non virtual call!
368 eRet
= typelib_TypeClass_VOID
;
370 case 0: // queryInterface() opt
372 typelib_TypeDescription
* pTD
= 0;
373 TYPELIB_DANGER_GET( &pTD
, reinterpret_cast<Type
*>( gpreg
[2] )->getTypeLibType() );
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
) );
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
;
395 TYPELIB_DANGER_RELEASE( pTD
);
397 } // else perform queryInterface()
400 typelib_InterfaceMethodTypeDescription
*pMethodTD
=
401 reinterpret_cast<typelib_InterfaceMethodTypeDescription
*>( aMemberDescr
.get() );
403 eRet
= cpp2uno_call( pCppI
, aMemberDescr
.get(),
404 pMethodTD
->pReturnTypeRef
,
407 gpreg
, fpreg
, ovrflw
, pRegisterReturn
);
414 throw RuntimeException( OUString::createFromAscii("no member description found!"),
415 reinterpret_cast<XInterface
*>( pCppI
) );
417 eRet
= typelib_TypeClass_VOID
;
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
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
);
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(
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
);
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
;
498 for ( sal_Int32 nPos
= 0; nPos
< type
->nMembers
; ++nPos
)
500 typelib_TypeDescription
* pTD
= 0;
502 TYPELIB_DANGER_GET( &pTD
, type
->ppMembers
[ nPos
] );
505 if ( typelib_TypeClass_INTERFACE_ATTRIBUTE
== pTD
->eTypeClass
)
507 typelib_InterfaceAttributeTypeDescription
*pAttrTD
=
508 reinterpret_cast<typelib_InterfaceAttributeTypeDescription
*>( pTD
);
511 (s
++)->fn
= code
+ writetoexecdiff
;
512 code
= codeSnippet( code
, nFunctionOffset
++, nVtableOffset
,
513 x86_64::return_in_hidden_param( pAttrTD
->pAttributeTypeRef
) );
515 if ( ! pAttrTD
->bReadOnly
)
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
) );
534 TYPELIB_DANGER_RELEASE( pTD
);
539 //==================================================================================================
540 void bridges::cpp_uno::shared::VtableFactory::flushCode(
541 unsigned char const *, unsigned char const * )