1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
24 #include <rtl/alloc.h>
25 #include <sal/log.hxx>
27 #include <com/sun/star/uno/genfunc.hxx>
28 #include <com/sun/star/uno/RuntimeException.hpp>
30 #include <typelib/typedescription.hxx>
33 #include <cppinterfaceproxy.hxx>
35 #include <vtablefactory.hxx>
41 using namespace ::osl
;
42 using namespace ::com::sun::star::uno
;
45 // Perform the UNO call
47 // We must convert the parameters stored in gpreg, fpreg and ovrflw to UNO
48 // arguments and call pThis->getUnoI()->pDispatcher.
50 // gpreg: [ret *], this, [gpr params]
51 // fpreg: [fpr params]
52 // ovrflw: [gpr or fpr params (properly aligned)]
54 // [ret *] is present when we are returning a structure bigger than 16 bytes
55 // Simple types are returned in rax, rdx (int), or xmm0, xmm1 (fp).
56 // Similarly structures <= 16 bytes are in rax, rdx, xmm0, xmm1 as necessary.
57 static typelib_TypeClass
cpp2uno_call(
58 bridges::cpp_uno::shared::CppInterfaceProxy
* pThis
,
59 const typelib_TypeDescription
* pMemberTypeDescr
,
60 typelib_TypeDescriptionReference
* pReturnTypeRef
, // 0 indicates void return
61 sal_Int32 nParams
, typelib_MethodParameter
* pParams
,
62 void ** gpreg
, void ** fpreg
, void ** ovrflw
,
63 sal_uInt64
* pRegisterReturn
/* space for register return */ )
65 unsigned int nr_gpr
= 0; //number of gpr registers used
66 unsigned int nr_fpr
= 0; //number of fpr registers used
69 typelib_TypeDescription
* pReturnTypeDescr
= nullptr;
71 TYPELIB_DANGER_GET( &pReturnTypeDescr
, pReturnTypeRef
);
73 void * pUnoReturn
= nullptr;
74 void * pCppReturn
= nullptr; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
76 if ( pReturnTypeDescr
)
78 if ( x86_64::return_in_hidden_param( pReturnTypeRef
) )
80 pCppReturn
= *gpreg
++;
83 pUnoReturn
= ( bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr
)
84 ? alloca( pReturnTypeDescr
->nSize
)
85 : pCppReturn
); // direct way
88 pUnoReturn
= pRegisterReturn
; // direct way for simple types
97 void ** pUnoArgs
= static_cast<void **>(alloca( 4 * sizeof(void *) * nParams
));
98 void ** pCppArgs
= pUnoArgs
+ nParams
;
99 // indices of values this have to be converted (interface conversion cpp<=>uno)
100 sal_Int32
* pTempIndices
= reinterpret_cast<sal_Int32
*>(pUnoArgs
+ (2 * nParams
));
101 // type descriptions for reconversions
102 typelib_TypeDescription
** ppTempParamTypeDescr
= reinterpret_cast<typelib_TypeDescription
**>(pUnoArgs
+ (3 * nParams
));
104 sal_Int32 nTempIndices
= 0;
106 for ( sal_Int32 nPos
= 0; nPos
< nParams
; ++nPos
)
108 const typelib_MethodParameter
& rParam
= pParams
[nPos
];
113 bool bFitsRegisters
=
115 x86_64::examine_argument( rParam
.pTypeRef
, false, nUsedGPR
, nUsedSSE
);
116 if ( !rParam
.bOut
&& bridges::cpp_uno::shared::isSimpleType( rParam
.pTypeRef
) ) // value
118 // Simple types must fit exactly one register on x86_64
119 assert(bFitsRegisters
&& ( ( nUsedSSE
== 1 && nUsedGPR
== 0 ) || ( nUsedSSE
== 0 && nUsedGPR
== 1 ) ));
123 if ( nr_fpr
< x86_64::MAX_SSE_REGS
)
125 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = fpreg
++;
129 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = ovrflw
++;
131 else if ( nUsedGPR
== 1 )
133 if ( nr_gpr
< x86_64::MAX_GPR_REGS
)
135 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = gpreg
++;
139 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = ovrflw
++;
142 else // struct <= 16 bytes || ptr to complex value || ref
144 typelib_TypeDescription
* pParamTypeDescr
= nullptr;
145 TYPELIB_DANGER_GET( &pParamTypeDescr
, rParam
.pTypeRef
);
148 if ( nr_gpr
< x86_64::MAX_GPR_REGS
)
150 pCppArgs
[nPos
] = pCppStack
= *gpreg
++;
154 pCppArgs
[nPos
] = pCppStack
= *ovrflw
++;
156 if (! rParam
.bIn
) // is pure out
158 // uno out is unconstructed mem!
159 pUnoArgs
[nPos
] = alloca( pParamTypeDescr
->nSize
);
160 pTempIndices
[nTempIndices
] = nPos
;
161 // will be released at reconversion
162 ppTempParamTypeDescr
[nTempIndices
++] = pParamTypeDescr
;
164 else if ( bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr
) ) // is in/inout
166 uno_copyAndConvertData( pUnoArgs
[nPos
] = alloca( pParamTypeDescr
->nSize
),
167 pCppStack
, pParamTypeDescr
,
168 pThis
->getBridge()->getCpp2Uno() );
169 pTempIndices
[nTempIndices
] = nPos
; // has to be reconverted
170 // will be released at reconversion
171 ppTempParamTypeDescr
[nTempIndices
++] = pParamTypeDescr
;
175 pUnoArgs
[nPos
] = pCppStack
;
177 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
183 uno_Any aUnoExc
; // Any will be constructed by callee
184 uno_Any
* pUnoExc
= &aUnoExc
;
186 // invoke uno dispatch call
187 (*pThis
->getUnoI()->pDispatcher
)( pThis
->getUnoI(), pMemberTypeDescr
, pUnoReturn
, pUnoArgs
, &pUnoExc
);
189 // in case an exception occurred...
192 // destruct temporary in/inout params
193 for ( ; nTempIndices
--; )
195 sal_Int32 nIndex
= pTempIndices
[nTempIndices
];
197 if (pParams
[nIndex
].bIn
) // is in/inout => was constructed
198 uno_destructData( pUnoArgs
[nIndex
], ppTempParamTypeDescr
[nTempIndices
], nullptr );
199 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr
[nTempIndices
] );
201 if (pReturnTypeDescr
)
202 TYPELIB_DANGER_RELEASE( pReturnTypeDescr
);
204 CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc
, pThis
->getBridge()->getUno2Cpp() ); // has to destruct the any
206 return typelib_TypeClass_VOID
;
208 else // else no exception occurred...
211 for ( ; nTempIndices
--; )
213 sal_Int32 nIndex
= pTempIndices
[nTempIndices
];
214 typelib_TypeDescription
* pParamTypeDescr
= ppTempParamTypeDescr
[nTempIndices
];
216 if ( pParams
[nIndex
].bOut
) // inout/out
218 // convert and assign
219 uno_destructData( pCppArgs
[nIndex
], pParamTypeDescr
, cpp_release
);
220 uno_copyAndConvertData( pCppArgs
[nIndex
], pUnoArgs
[nIndex
], pParamTypeDescr
,
221 pThis
->getBridge()->getUno2Cpp() );
223 // destroy temp uno param
224 uno_destructData( pUnoArgs
[nIndex
], pParamTypeDescr
, nullptr );
226 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
229 if ( pCppReturn
) // has complex return
231 if ( pUnoReturn
!= pCppReturn
) // needs reconversion
233 uno_copyAndConvertData( pCppReturn
, pUnoReturn
, pReturnTypeDescr
,
234 pThis
->getBridge()->getUno2Cpp() );
235 // destroy temp uno return
236 uno_destructData( pUnoReturn
, pReturnTypeDescr
, nullptr );
238 // complex return ptr is set to return reg
239 *reinterpret_cast<void **>(pRegisterReturn
) = pCppReturn
;
241 if ( pReturnTypeDescr
)
243 typelib_TypeClass eRet
= pReturnTypeDescr
->eTypeClass
;
244 TYPELIB_DANGER_RELEASE( pReturnTypeDescr
);
248 return typelib_TypeClass_VOID
;
252 typelib_TypeClass
cpp_vtable_call(
253 sal_Int32 nFunctionIndex
, sal_Int32 nVtableOffset
,
254 void ** gpreg
, void ** fpreg
, void ** ovrflw
,
255 sal_uInt64
* pRegisterReturn
/* space for register return */ )
257 // gpreg: [ret *], this, [other gpr params]
258 // fpreg: [fpr params]
259 // ovrflw: [gpr or fpr params (properly aligned)]
261 if ( nFunctionIndex
& 0x80000000 )
263 nFunctionIndex
&= 0x7fffffff;
270 pThis
= static_cast<char *>( pThis
) - nVtableOffset
;
272 bridges::cpp_uno::shared::CppInterfaceProxy
* pCppI
=
273 bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( pThis
);
275 typelib_InterfaceTypeDescription
* pTypeDescr
= pCppI
->getTypeDescr();
277 if ( nFunctionIndex
>= pTypeDescr
->nMapFunctionIndexToMemberIndex
)
281 "illegal " << OUString::unacquired(&pTypeDescr
->aBase
.pTypeName
)
282 << " vtable index " << nFunctionIndex
<< "/"
283 << pTypeDescr
->nMapFunctionIndexToMemberIndex
);
284 throw RuntimeException(
285 ("illegal " + OUString::unacquired(&pTypeDescr
->aBase
.pTypeName
)
286 + " vtable index " + OUString::number(nFunctionIndex
) + "/"
287 + OUString::number(pTypeDescr
->nMapFunctionIndexToMemberIndex
)),
288 reinterpret_cast<XInterface
*>( pCppI
) );
291 // determine called method
292 sal_Int32 nMemberPos
= pTypeDescr
->pMapFunctionIndexToMemberIndex
[nFunctionIndex
];
293 assert(nMemberPos
< pTypeDescr
->nAllMembers
);
295 TypeDescription
aMemberDescr( pTypeDescr
->ppAllMembers
[nMemberPos
] );
297 typelib_TypeClass eRet
;
298 switch ( aMemberDescr
.get()->eTypeClass
)
300 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
302 typelib_TypeDescriptionReference
*pAttrTypeRef
=
303 reinterpret_cast<typelib_InterfaceAttributeTypeDescription
*>( aMemberDescr
.get() )->pAttributeTypeRef
;
305 if ( pTypeDescr
->pMapMemberIndexToFunctionIndex
[nMemberPos
] == nFunctionIndex
)
308 eRet
= cpp2uno_call( pCppI
, aMemberDescr
.get(), pAttrTypeRef
,
309 0, nullptr, // no params
310 gpreg
, fpreg
, ovrflw
, pRegisterReturn
);
315 typelib_MethodParameter aParam
;
316 aParam
.pTypeRef
= pAttrTypeRef
;
320 eRet
= cpp2uno_call( pCppI
, aMemberDescr
.get(),
321 nullptr, // indicates void return
323 gpreg
, fpreg
, ovrflw
, pRegisterReturn
);
327 case typelib_TypeClass_INTERFACE_METHOD
:
330 switch ( nFunctionIndex
)
333 pCppI
->acquireProxy(); // non virtual call!
334 eRet
= typelib_TypeClass_VOID
;
337 pCppI
->releaseProxy(); // non virtual call!
338 eRet
= typelib_TypeClass_VOID
;
340 case 0: // queryInterface() opt
342 typelib_TypeDescription
* pTD
= nullptr;
343 TYPELIB_DANGER_GET( &pTD
, static_cast<Type
*>( gpreg
[2] )->getTypeLibType() );
346 XInterface
* pInterface
= nullptr;
347 (*pCppI
->getBridge()->getCppEnv()->getRegisteredInterface
)
348 ( pCppI
->getBridge()->getCppEnv(),
349 reinterpret_cast<void **>(&pInterface
),
350 pCppI
->getOid().pData
,
351 reinterpret_cast<typelib_InterfaceTypeDescription
*>( pTD
) );
355 ::uno_any_construct( static_cast<uno_Any
*>( gpreg
[0] ),
356 &pInterface
, pTD
, cpp_acquire
);
358 pInterface
->release();
359 TYPELIB_DANGER_RELEASE( pTD
);
361 reinterpret_cast<void **>( pRegisterReturn
)[0] = gpreg
[0];
362 eRet
= typelib_TypeClass_ANY
;
365 TYPELIB_DANGER_RELEASE( pTD
);
367 [[fallthrough
]]; // else perform queryInterface()
371 typelib_InterfaceMethodTypeDescription
*pMethodTD
=
372 reinterpret_cast<typelib_InterfaceMethodTypeDescription
*>( aMemberDescr
.get() );
374 eRet
= cpp2uno_call( pCppI
, aMemberDescr
.get(),
375 pMethodTD
->pReturnTypeRef
,
378 gpreg
, fpreg
, ovrflw
, pRegisterReturn
);
385 throw RuntimeException("no member description found!",
386 reinterpret_cast<XInterface
*>( pCppI
) );
393 const int codeSnippetSize
= 24;
395 // Generate a trampoline that redirects method calls to
396 // privateSnippetExecutor().
398 // privateSnippetExecutor() saves all the registers that are used for
399 // parameter passing on x86_64, and calls the cpp_vtable_call().
400 // When it returns, privateSnippetExecutor() sets the return value.
402 // Note: The code snippet we build here must not create a stack frame,
403 // otherwise the UNO exceptions stop working thanks to non-existing
405 static unsigned char * codeSnippet( unsigned char * code
,
406 sal_Int32 nFunctionIndex
, sal_Int32 nVtableOffset
,
407 bool bHasHiddenParam
)
409 sal_uInt64 nOffsetAndIndex
= ( static_cast<sal_uInt64
>(nVtableOffset
) << 32 ) | static_cast<sal_uInt64
>(nFunctionIndex
);
411 if ( bHasHiddenParam
)
412 nOffsetAndIndex
|= 0x80000000;
414 // movq $<nOffsetAndIndex>, %r10
415 *reinterpret_cast<sal_uInt16
*>( code
) = 0xba49;
416 *reinterpret_cast<sal_uInt16
*>( code
+ 2 ) = nOffsetAndIndex
& 0xFFFF;
417 *reinterpret_cast<sal_uInt32
*>( code
+ 4 ) = nOffsetAndIndex
>> 16;
418 *reinterpret_cast<sal_uInt16
*>( code
+ 8 ) = nOffsetAndIndex
>> 48;
420 // movq $<address of the privateSnippetExecutor>, %r11
421 *reinterpret_cast<sal_uInt16
*>( code
+ 10 ) = 0xbb49;
422 *reinterpret_cast<sal_uInt32
*>( code
+ 12 )
423 = reinterpret_cast<sal_uInt64
>(privateSnippetExecutor
);
424 *reinterpret_cast<sal_uInt32
*>( code
+ 16 )
425 = reinterpret_cast<sal_uInt64
>(privateSnippetExecutor
) >> 32;
428 *reinterpret_cast<sal_uInt32
*>( code
+ 20 ) = 0x00e3ff49;
430 #if OSL_DEBUG_LEVEL > 1
432 "==> codeSnippet, functionIndex=%d%s, vtableOffset=%d\n",
433 nFunctionIndex
, (bHasHiddenParam
? "|0x80000000":""), nVtableOffset
);
436 return code
+ codeSnippetSize
;
439 struct bridges::cpp_uno::shared::VtableFactory::Slot
{ void * fn
; };
441 bridges::cpp_uno::shared::VtableFactory::Slot
*
442 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block
)
444 return static_cast< Slot
* >(block
) + 2;
447 std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(
450 return (slotCount
+ 2) * sizeof (Slot
) + slotCount
* codeSnippetSize
;
453 bridges::cpp_uno::shared::VtableFactory::Slot
*
454 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
455 void * block
, sal_Int32 slotCount
, sal_Int32
,
456 typelib_InterfaceTypeDescription
*)
458 Slot
* slots
= mapBlockToVtable(block
);
459 slots
[-2].fn
= nullptr;
460 slots
[-1].fn
= nullptr;
461 return slots
+ slotCount
;
465 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
466 Slot
** slots
, unsigned char * code
,
467 typelib_InterfaceTypeDescription
const * type
, sal_Int32 nFunctionOffset
,
468 sal_Int32 functionCount
, sal_Int32 nVtableOffset
)
470 const sal_PtrDiff writetoexecdiff
= 0;
471 (*slots
) -= functionCount
;
473 for ( sal_Int32 nPos
= 0; nPos
< type
->nMembers
; ++nPos
)
475 typelib_TypeDescription
* pTD
= nullptr;
477 TYPELIB_DANGER_GET( &pTD
, type
->ppMembers
[ nPos
] );
480 if ( typelib_TypeClass_INTERFACE_ATTRIBUTE
== pTD
->eTypeClass
)
482 typelib_InterfaceAttributeTypeDescription
*pAttrTD
=
483 reinterpret_cast<typelib_InterfaceAttributeTypeDescription
*>( pTD
);
486 (s
++)->fn
= code
+ writetoexecdiff
;
487 code
= codeSnippet( code
, nFunctionOffset
++, nVtableOffset
,
488 x86_64::return_in_hidden_param( pAttrTD
->pAttributeTypeRef
) );
490 if ( ! pAttrTD
->bReadOnly
)
493 (s
++)->fn
= code
+ writetoexecdiff
;
494 code
= codeSnippet( code
, nFunctionOffset
++, nVtableOffset
, false );
497 else if ( typelib_TypeClass_INTERFACE_METHOD
== pTD
->eTypeClass
)
499 typelib_InterfaceMethodTypeDescription
*pMethodTD
=
500 reinterpret_cast<typelib_InterfaceMethodTypeDescription
*>( pTD
);
502 (s
++)->fn
= code
+ writetoexecdiff
;
503 code
= codeSnippet( code
, nFunctionOffset
++, nVtableOffset
,
504 x86_64::return_in_hidden_param( pMethodTD
->pReturnTypeRef
) );
509 TYPELIB_DANGER_RELEASE( pTD
);
514 void bridges::cpp_uno::shared::VtableFactory::flushCode(
515 SAL_UNUSED_PARAMETER
unsigned char const *,
516 SAL_UNUSED_PARAMETER
unsigned char const * )
519 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */