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 .
20 #include <sal/alloca.h>
25 #include <rtl/alloc.h>
27 #include <com/sun/star/uno/genfunc.hxx>
28 #include <com/sun/star/uno/RuntimeException.hpp>
29 #include <o3tl/runtimetooustring.hxx>
34 #include <unointerfaceproxy.hxx>
35 #include <vtables.hxx>
38 #include "callvirtualmethod.hxx"
41 using namespace ::com::sun::star::uno
;
45 // Functions for easier insertion of values to registers or stack
46 // pSV - pointer to the source
47 // nr - order of the value [will be increased if stored to register]
48 // pFPR, pGPR - pointer to the registers
49 // pDS - pointer to the stack [will be increased if stored here]
51 // The value in %xmm register is already prepared to be retrieved as a float,
52 // thus we treat float and double the same
53 void INSERT_FLOAT_DOUBLE(
54 void const * pSV
, sal_uInt32
& nr
, double * pFPR
, sal_uInt64
*& pDS
)
56 if ( nr
< x86_64::MAX_SSE_REGS
)
57 pFPR
[nr
++] = *static_cast<double const *>( pSV
);
59 *pDS
++ = *static_cast<sal_uInt64
const *>( pSV
); // verbatim!
63 void const * pSV
, sal_uInt32
& nr
, sal_uInt64
* pGPR
, sal_uInt64
*& pDS
)
65 if ( nr
< x86_64::MAX_GPR_REGS
)
66 pGPR
[nr
++] = *static_cast<sal_uInt64
const *>( pSV
);
68 *pDS
++ = *static_cast<sal_uInt64
const *>( pSV
);
72 void const * pSV
, sal_uInt32
& nr
, sal_uInt64
* pGPR
, sal_uInt64
*& pDS
)
74 if ( nr
< x86_64::MAX_GPR_REGS
)
75 pGPR
[nr
++] = *static_cast<sal_uInt32
const *>( pSV
);
77 *pDS
++ = *static_cast<sal_uInt32
const *>( pSV
);
81 void const * pSV
, sal_uInt32
& nr
, sal_uInt64
* pGPR
, sal_uInt64
*& pDS
)
83 if ( nr
< x86_64::MAX_GPR_REGS
)
84 pGPR
[nr
++] = *static_cast<sal_uInt16
const *>( pSV
);
86 *pDS
++ = *static_cast<sal_uInt16
const *>( pSV
);
90 void const * pSV
, sal_uInt32
& nr
, sal_uInt64
* pGPR
, sal_uInt64
*& pDS
)
92 if ( nr
< x86_64::MAX_GPR_REGS
)
93 pGPR
[nr
++] = *static_cast<sal_uInt8
const *>( pSV
);
95 *pDS
++ = *static_cast<sal_uInt8
const *>( pSV
);
100 static void cpp_call(
101 bridges::cpp_uno::shared::UnoInterfaceProxy
* pThis
,
102 bridges::cpp_uno::shared::VtableSlot aVtableSlot
,
103 typelib_TypeDescriptionReference
* pReturnTypeRef
,
104 sal_Int32 nParams
, typelib_MethodParameter
* pParams
,
105 void * pUnoReturn
, void * pUnoArgs
[], uno_Any
** ppUnoExc
)
107 // Maximum space for [complex ret ptr], values | ptr ...
108 // (but will be used less - some of the values will be in pGPR and pFPR)
109 sal_uInt64
*pStack
= static_cast<sal_uInt64
*>(__builtin_alloca( (nParams
+ 3) * sizeof(sal_uInt64
) ));
110 sal_uInt64
*pStackStart
= pStack
;
112 sal_uInt64 pGPR
[x86_64::MAX_GPR_REGS
];
115 double pFPR
[x86_64::MAX_SSE_REGS
];
119 typelib_TypeDescription
* pReturnTypeDescr
= nullptr;
120 TYPELIB_DANGER_GET( &pReturnTypeDescr
, pReturnTypeRef
);
121 assert(pReturnTypeDescr
);
123 void * pCppReturn
= nullptr; // if != 0 && != pUnoReturn, needs reconversion (see below)
125 bool bSimpleReturn
= true;
126 if ( pReturnTypeDescr
)
128 if ( x86_64::return_in_hidden_param( pReturnTypeRef
) )
129 bSimpleReturn
= false;
132 pCppReturn
= pUnoReturn
; // direct way for simple types
135 // complex return via ptr
136 pCppReturn
= bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr
)?
137 __builtin_alloca( pReturnTypeDescr
->nSize
) : pUnoReturn
;
138 INSERT_INT64( &pCppReturn
, nGPR
, pGPR
, pStack
);
142 // Push "this" pointer
143 void * pAdjustedThisPtr
= reinterpret_cast< void ** >( pThis
->getCppI() ) + aVtableSlot
.offset
;
144 INSERT_INT64( &pAdjustedThisPtr
, nGPR
, pGPR
, pStack
);
147 void ** pCppArgs
= static_cast<void **>(alloca( 3 * sizeof(void *) * nParams
));
148 // Indices of values this have to be converted (interface conversion cpp<=>uno)
149 sal_Int32
* pTempIndices
= reinterpret_cast<sal_Int32
*>(pCppArgs
+ nParams
);
150 // Type descriptions for reconversions
151 typelib_TypeDescription
** ppTempParamTypeDescr
= reinterpret_cast<typelib_TypeDescription
**>(pCppArgs
+ (2 * nParams
));
153 sal_Int32 nTempIndices
= 0;
155 for ( sal_Int32 nPos
= 0; nPos
< nParams
; ++nPos
)
157 const typelib_MethodParameter
& rParam
= pParams
[nPos
];
158 typelib_TypeDescription
* pParamTypeDescr
= nullptr;
159 TYPELIB_DANGER_GET( &pParamTypeDescr
, rParam
.pTypeRef
);
161 if (!rParam
.bOut
&& bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr
))
163 uno_copyAndConvertData( pCppArgs
[nPos
] = alloca( 8 ), pUnoArgs
[nPos
], pParamTypeDescr
,
164 pThis
->getBridge()->getUno2Cpp() );
166 switch (pParamTypeDescr
->eTypeClass
)
168 case typelib_TypeClass_HYPER
:
169 case typelib_TypeClass_UNSIGNED_HYPER
:
170 INSERT_INT64( pCppArgs
[nPos
], nGPR
, pGPR
, pStack
);
172 case typelib_TypeClass_LONG
:
173 case typelib_TypeClass_UNSIGNED_LONG
:
174 case typelib_TypeClass_ENUM
:
175 INSERT_INT32( pCppArgs
[nPos
], nGPR
, pGPR
, pStack
);
177 case typelib_TypeClass_SHORT
:
178 case typelib_TypeClass_CHAR
:
179 case typelib_TypeClass_UNSIGNED_SHORT
:
180 INSERT_INT16( pCppArgs
[nPos
], nGPR
, pGPR
, pStack
);
182 case typelib_TypeClass_BOOLEAN
:
183 case typelib_TypeClass_BYTE
:
184 INSERT_INT8( pCppArgs
[nPos
], nGPR
, pGPR
, pStack
);
186 case typelib_TypeClass_FLOAT
:
187 case typelib_TypeClass_DOUBLE
:
188 INSERT_FLOAT_DOUBLE( pCppArgs
[nPos
], nFPR
, pFPR
, pStack
);
195 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
197 else // ptr to complex value | ref
199 if (! rParam
.bIn
) // is pure out
201 // cpp out is constructed mem, uno out is not!
203 pCppArgs
[nPos
] = alloca( pParamTypeDescr
->nSize
),
205 pTempIndices
[nTempIndices
] = nPos
; // default constructed for cpp call
206 // will be released at reconversion
207 ppTempParamTypeDescr
[nTempIndices
++] = pParamTypeDescr
;
210 else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr
))
212 uno_copyAndConvertData(
213 pCppArgs
[nPos
] = alloca( pParamTypeDescr
->nSize
),
214 pUnoArgs
[nPos
], pParamTypeDescr
, pThis
->getBridge()->getUno2Cpp() );
216 pTempIndices
[nTempIndices
] = nPos
; // has to be reconverted
217 // will be released at reconversion
218 ppTempParamTypeDescr
[nTempIndices
++] = pParamTypeDescr
;
222 pCppArgs
[nPos
] = pUnoArgs
[nPos
];
224 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
226 INSERT_INT64( &(pCppArgs
[nPos
]), nGPR
, pGPR
, pStack
);
233 CPPU_CURRENT_NAMESPACE::callVirtualMethod(
234 pAdjustedThisPtr
, aVtableSlot
.index
,
235 pCppReturn
, pReturnTypeRef
, bSimpleReturn
,
236 pStackStart
, ( pStack
- pStackStart
),
238 } catch (const Exception
&) {
240 } catch (const std::exception
& e
) {
241 throw RuntimeException(
242 "C++ code threw " + o3tl::runtimeToOUString(typeid(e
).name())
243 + ": " + o3tl::runtimeToOUString(e
.what()));
245 throw RuntimeException("C++ code threw unknown exception");
250 // reconvert temporary params
251 for ( ; nTempIndices
--; )
253 sal_Int32 nIndex
= pTempIndices
[nTempIndices
];
254 typelib_TypeDescription
* pParamTypeDescr
= ppTempParamTypeDescr
[nTempIndices
];
256 if (pParams
[nIndex
].bIn
)
258 if (pParams
[nIndex
].bOut
) // inout
260 uno_destructData( pUnoArgs
[nIndex
], pParamTypeDescr
, nullptr ); // destroy uno value
261 uno_copyAndConvertData( pUnoArgs
[nIndex
], pCppArgs
[nIndex
], pParamTypeDescr
,
262 pThis
->getBridge()->getCpp2Uno() );
267 uno_copyAndConvertData( pUnoArgs
[nIndex
], pCppArgs
[nIndex
], pParamTypeDescr
,
268 pThis
->getBridge()->getCpp2Uno() );
270 // destroy temp cpp param => cpp: every param was constructed
271 uno_destructData( pCppArgs
[nIndex
], pParamTypeDescr
, cpp_release
);
273 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
276 if (pCppReturn
&& pUnoReturn
!= pCppReturn
)
278 uno_copyAndConvertData( pUnoReturn
, pCppReturn
, pReturnTypeDescr
,
279 pThis
->getBridge()->getCpp2Uno() );
280 uno_destructData( pCppReturn
, pReturnTypeDescr
, cpp_release
);
285 // fill uno exception
286 CPPU_CURRENT_NAMESPACE::fillUnoException(*ppUnoExc
, pThis
->getBridge()->getCpp2Uno());
289 for ( ; nTempIndices
--; )
291 sal_Int32 nIndex
= pTempIndices
[nTempIndices
];
292 // destroy temp cpp param => cpp: every param was constructed
293 uno_destructData( pCppArgs
[nIndex
], ppTempParamTypeDescr
[nTempIndices
], cpp_release
);
294 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr
[nTempIndices
] );
297 if (pReturnTypeDescr
)
298 TYPELIB_DANGER_RELEASE( pReturnTypeDescr
);
303 namespace bridges
{ namespace cpp_uno
{ namespace shared
{
305 void unoInterfaceProxyDispatch(
306 uno_Interface
* pUnoI
, const typelib_TypeDescription
* pMemberDescr
,
307 void * pReturn
, void * pArgs
[], uno_Any
** ppException
)
310 bridges::cpp_uno::shared::UnoInterfaceProxy
* pThis
311 = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy
* >(pUnoI
);
312 #if OSL_DEBUG_LEVEL > 0
313 typelib_InterfaceTypeDescription
* pTypeDescr
= pThis
->pTypeDescr
;
316 switch (pMemberDescr
->eTypeClass
)
318 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
320 #if OSL_DEBUG_LEVEL > 0
321 // determine vtable call index
322 sal_Int32 nMemberPos
= reinterpret_cast<typelib_InterfaceMemberTypeDescription
const *>(pMemberDescr
)->nPosition
;
323 assert(nMemberPos
< pTypeDescr
->nAllMembers
);
325 VtableSlot
aVtableSlot(
328 typelib_InterfaceAttributeTypeDescription
const * >(
333 // dependent dispatch
336 reinterpret_cast<typelib_InterfaceAttributeTypeDescription
const *>(pMemberDescr
)->pAttributeTypeRef
,
337 0, nullptr, // no params
338 pReturn
, pArgs
, ppException
);
343 typelib_MethodParameter aParam
;
345 reinterpret_cast<typelib_InterfaceAttributeTypeDescription
const *>(pMemberDescr
)->pAttributeTypeRef
;
349 typelib_TypeDescriptionReference
* pReturnTypeRef
= nullptr;
350 OUString
aVoidName("void");
351 typelib_typedescriptionreference_new(
352 &pReturnTypeRef
, typelib_TypeClass_VOID
, aVoidName
.pData
);
354 // dependent dispatch
355 aVtableSlot
.index
+= 1; // get, then set method
357 pThis
, aVtableSlot
, // get, then set method
360 pReturn
, pArgs
, ppException
);
362 typelib_typedescriptionreference_release( pReturnTypeRef
);
367 case typelib_TypeClass_INTERFACE_METHOD
:
369 #if OSL_DEBUG_LEVEL > 0
370 // determine vtable call index
371 sal_Int32 nMemberPos
= reinterpret_cast<typelib_InterfaceMemberTypeDescription
const *>(pMemberDescr
)->nPosition
;
372 assert(nMemberPos
< pTypeDescr
->nAllMembers
);
374 VtableSlot
aVtableSlot(
377 typelib_InterfaceMethodTypeDescription
const * >(
380 switch (aVtableSlot
.index
)
383 case 1: // acquire uno interface
384 (*pUnoI
->acquire
)( pUnoI
);
385 *ppException
= nullptr;
387 case 2: // release uno interface
388 (*pUnoI
->release
)( pUnoI
);
389 *ppException
= nullptr;
391 case 0: // queryInterface() opt
393 typelib_TypeDescription
* pTD
= nullptr;
394 TYPELIB_DANGER_GET( &pTD
, static_cast< Type
* >( pArgs
[0] )->getTypeLibType() );
397 uno_Interface
* pInterface
= nullptr;
398 (*pThis
->getBridge()->getUnoEnv()->getRegisteredInterface
)(
399 pThis
->getBridge()->getUnoEnv(),
400 reinterpret_cast<void **>(&pInterface
), pThis
->oid
.pData
, reinterpret_cast<typelib_InterfaceTypeDescription
*>(pTD
) );
405 static_cast< uno_Any
* >( pReturn
),
406 &pInterface
, pTD
, nullptr );
407 (*pInterface
->release
)( pInterface
);
408 TYPELIB_DANGER_RELEASE( pTD
);
409 *ppException
= nullptr;
412 TYPELIB_DANGER_RELEASE( pTD
);
414 [[fallthrough
]]; // else perform queryInterface()
417 // dependent dispatch
420 reinterpret_cast<typelib_InterfaceMethodTypeDescription
const *>(pMemberDescr
)->pReturnTypeRef
,
421 reinterpret_cast<typelib_InterfaceMethodTypeDescription
const *>(pMemberDescr
)->nParams
,
422 reinterpret_cast<typelib_InterfaceMethodTypeDescription
const *>(pMemberDescr
)->pParams
,
423 pReturn
, pArgs
, ppException
);
429 ::com::sun::star::uno::RuntimeException
aExc(
430 "illegal member type description!",
431 ::com::sun::star::uno::Reference
< ::com::sun::star::uno::XInterface
>() );
433 Type
const & rExcType
= cppu::UnoType
<decltype(aExc
)>::get();
434 // binary identical null reference
435 ::uno_type_any_construct( *ppException
, &aExc
, rExcType
.getTypeLibType(), nullptr );
442 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */