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 .
21 #include <rtl/alloc.h>
23 #include <com/sun/star/uno/genfunc.hxx>
24 #include <com/sun/star/uno/Exception.hpp>
25 #include "com/sun/star/uno/RuntimeException.hpp"
26 #include <o3tl/runtimetooustring.hxx>
31 #include <unointerfaceproxy.hxx>
32 #include <vtables.hxx>
41 using namespace ::com::sun::star::uno
;
43 void callVirtualMethod(void * pThis
, sal_uInt32 nVtableIndex
,
44 void * pRegisterReturn
, typelib_TypeDescription
*pReturnTypeDescr
, bool bRegisterReturn
,
45 sal_uInt32
*pStack
, sal_uInt32 nStack
, sal_uInt32
*pGPR
, double *pFPR
);
47 #define INSERT_INT32( pSV, nr, pGPR, pDS, bOverflow )\
48 if (nr < hppa::MAX_WORDS_IN_REGS) \
50 pGPR[nr++] = *reinterpret_cast<sal_uInt32 *>( pSV ); \
55 *pDS++ = *reinterpret_cast<sal_uInt32 *>( pSV );
57 #define INSERT_INT64( pSV, nr, pGPR, pDS, pStart, bOverflow )\
58 if ( (nr < hppa::MAX_WORDS_IN_REGS) && (nr % 2) ) \
62 if ( nr < hppa::MAX_WORDS_IN_REGS ) \
64 pGPR[nr++] = *reinterpret_cast<sal_uInt32 *>( pSV ); \
65 pGPR[nr++] = *(reinterpret_cast<sal_uInt32 *>( pSV ) + 1); \
71 if ( (pDS - pStart) % 2) \
73 *pDS++ = reinterpret_cast<sal_uInt32 *>( pSV )[1]; \
74 *pDS++ = reinterpret_cast<sal_uInt32 *>( pSV )[0]; \
77 #define INSERT_FLOAT( pSV, nr, pFPR, pDS, bOverflow ) \
78 if (nr < hppa::MAX_WORDS_IN_REGS) \
80 sal_uInt32 *pDouble = (sal_uInt32 *)&(pFPR[nr++]); \
81 pDouble[0] = *reinterpret_cast<sal_uInt32 *>( pSV ); \
86 *pDS++ = *reinterpret_cast<sal_uInt32 *>( pSV );
88 #define INSERT_DOUBLE( pSV, nr, pFPR, pDS, pStart, bOverflow ) \
89 if ( (nr < hppa::MAX_WORDS_IN_REGS) && (nr % 2) ) \
93 if ( nr < hppa::MAX_WORDS_IN_REGS ) \
95 sal_uInt32 *pDouble = (sal_uInt32 *)&(pFPR[nr+1]); \
96 pDouble[0] = *reinterpret_cast<sal_uInt32 *>( pSV ); \
97 pDouble[1] = *(reinterpret_cast<sal_uInt32 *>( pSV ) + 1); \
104 if ( (pDS - pStart) % 2) \
106 *pDS++ = reinterpret_cast<sal_uInt32 *>( pSV )[1]; \
107 *pDS++ = reinterpret_cast<sal_uInt32 *>( pSV )[0]; \
110 #define INSERT_INT16( pSV, nr, pGPR, pDS, bOverflow ) \
111 if ( nr < hppa::MAX_WORDS_IN_REGS ) \
112 pGPR[nr++] = *reinterpret_cast<sal_uInt16 *>( pSV ); \
116 *pDS++ = *reinterpret_cast<sal_uInt16 *>( pSV );
118 #define INSERT_INT8( pSV, nr, pGPR, pDS, bOverflow ) \
119 if ( nr < hppa::MAX_WORDS_IN_REGS ) \
120 pGPR[nr++] = *reinterpret_cast<sal_uInt8 *>( pSV ); \
124 *pDS++ = *reinterpret_cast<sal_uInt8 *>( pSV );
128 bool is_complex_struct(const typelib_TypeDescription
* type
)
130 const typelib_CompoundTypeDescription
* p
131 = reinterpret_cast< const typelib_CompoundTypeDescription
* >(type
);
132 for (sal_Int32 i
= 0; i
< p
->nMembers
; ++i
)
134 if (p
->ppTypeRefs
[i
]->eTypeClass
== typelib_TypeClass_STRUCT
||
135 p
->ppTypeRefs
[i
]->eTypeClass
== typelib_TypeClass_EXCEPTION
)
137 typelib_TypeDescription
* t
= 0;
138 TYPELIB_DANGER_GET(&t
, p
->ppTypeRefs
[i
]);
139 bool b
= is_complex_struct(t
);
140 TYPELIB_DANGER_RELEASE(t
);
145 else if (!bridges::cpp_uno::shared::isSimpleType(p
->ppTypeRefs
[i
]->eTypeClass
))
148 if (p
->pBaseTypeDescription
!= 0)
149 return is_complex_struct(&p
->pBaseTypeDescription
->aBase
);
153 bool isRegisterReturn( typelib_TypeDescriptionReference
*pTypeRef
)
155 if (bridges::cpp_uno::shared::isSimpleType(pTypeRef
))
157 else if (pTypeRef
->eTypeClass
== typelib_TypeClass_STRUCT
|| pTypeRef
->eTypeClass
== typelib_TypeClass_EXCEPTION
)
159 typelib_TypeDescription
* pTypeDescr
= 0;
160 TYPELIB_DANGER_GET( &pTypeDescr
, pTypeRef
);
162 /* If the struct is larger than 8 bytes, then there is a buffer at r8 to stick the return value into */
163 bool bRet
= pTypeDescr
->nSize
<= 8 && !is_complex_struct(pTypeDescr
);
165 TYPELIB_DANGER_RELEASE( pTypeDescr
);
175 static void cpp_call(
176 bridges::cpp_uno::shared::UnoInterfaceProxy
* pThis
,
177 bridges::cpp_uno::shared::VtableSlot aVtableSlot
,
178 typelib_TypeDescriptionReference
* pReturnTypeRef
,
179 sal_Int32 nParams
, typelib_MethodParameter
* pParams
,
180 void * pUnoReturn
, void * pUnoArgs
[], uno_Any
** ppUnoExc
)
182 // max space for: [complex ret ptr], values|ptr ...
183 sal_uInt32
* pStack
= (sal_uInt32
*)__builtin_alloca(
184 sizeof(sal_Int32
) + ((nParams
+2) * sizeof(sal_Int64
)) );
185 sal_uInt32
* pStackStart
= pStack
;
187 sal_uInt32 pGPR
[hppa::MAX_GPR_REGS
];
188 double pFPR
[hppa::MAX_SSE_REGS
];
192 typelib_TypeDescription
* pReturnTypeDescr
= 0;
193 TYPELIB_DANGER_GET( &pReturnTypeDescr
, pReturnTypeRef
);
194 assert(pReturnTypeDescr
);
196 void * pCppReturn
= 0; // if != 0 && != pUnoReturn, needs reconversion
197 bool bOverflow
= false;
198 bool bRegisterReturn
= true;
200 if (pReturnTypeDescr
)
203 bRegisterReturn
= hppa::isRegisterReturn(pReturnTypeRef
);
205 pCppReturn
= pUnoReturn
; // direct way for simple types
208 // complex return via ptr
209 pCppReturn
= (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr
)
210 ? __builtin_alloca( pReturnTypeDescr
->nSize
)
211 : pUnoReturn
); // direct way
215 void * pAdjustedThisPtr
= reinterpret_cast< void ** >(pThis
->getCppI())
216 + aVtableSlot
.offset
;
217 INSERT_INT32( &pAdjustedThisPtr
, nRegs
, pGPR
, pStack
, bOverflow
);
220 static_assert(sizeof(void *) == sizeof(sal_Int32
), "### unexpected size!");
222 void ** pCppArgs
= (void **)alloca( 3 * sizeof(void *) * nParams
);
223 // indices of values this have to be converted (interface conversion cpp<=>uno)
224 sal_Int32
* pTempIndices
= (sal_Int32
*)(pCppArgs
+ nParams
);
225 // type descriptions for reconversions
226 typelib_TypeDescription
** ppTempParamTypeDescr
= (typelib_TypeDescription
**)(pCppArgs
+ (2 * nParams
));
228 sal_Int32 nTempIndices
= 0;
230 for ( sal_Int32 nPos
= 0; nPos
< nParams
; ++nPos
)
232 const typelib_MethodParameter
& rParam
= pParams
[nPos
];
233 typelib_TypeDescription
* pParamTypeDescr
= 0;
234 TYPELIB_DANGER_GET( &pParamTypeDescr
, rParam
.pTypeRef
);
236 if (!rParam
.bOut
&& bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr
))
238 uno_copyAndConvertData( pCppArgs
[nPos
] = alloca(8), pUnoArgs
[nPos
],
239 pParamTypeDescr
, pThis
->getBridge()->getUno2Cpp() );
241 switch (pParamTypeDescr
->eTypeClass
)
243 case typelib_TypeClass_HYPER
:
244 case typelib_TypeClass_UNSIGNED_HYPER
:
245 #if OSL_DEBUG_LEVEL > 2
246 fprintf(stderr
, "hyper is %llx\n", *((long long*)pCppArgs
[nPos
]));
248 INSERT_INT64( pCppArgs
[nPos
], nRegs
, pGPR
, pStack
, pStackStart
, bOverflow
);
250 case typelib_TypeClass_LONG
:
251 case typelib_TypeClass_UNSIGNED_LONG
:
252 case typelib_TypeClass_ENUM
:
253 #if OSL_DEBUG_LEVEL > 2
254 fprintf(stderr
, "long is %x\n", pCppArgs
[nPos
]);
256 INSERT_INT32( pCppArgs
[nPos
], nRegs
, pGPR
, pStack
, bOverflow
);
258 case typelib_TypeClass_SHORT
:
259 case typelib_TypeClass_CHAR
:
260 case typelib_TypeClass_UNSIGNED_SHORT
:
261 INSERT_INT16( pCppArgs
[nPos
], nRegs
, pGPR
, pStack
, bOverflow
);
263 case typelib_TypeClass_BOOLEAN
:
264 case typelib_TypeClass_BYTE
:
265 INSERT_INT8( pCppArgs
[nPos
], nRegs
, pGPR
, pStack
, bOverflow
);
267 case typelib_TypeClass_FLOAT
:
268 INSERT_FLOAT( pCppArgs
[nPos
], nRegs
, pFPR
, pStack
, bOverflow
);
270 case typelib_TypeClass_DOUBLE
:
271 INSERT_DOUBLE( pCppArgs
[nPos
], nRegs
, pFPR
, pStack
, pStackStart
, bOverflow
);
277 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
279 else // ptr to complex value | ref
281 if (! rParam
.bIn
) // is pure out
283 // cpp out is constructed mem, uno out is not!
285 pCppArgs
[nPos
] = alloca( pParamTypeDescr
->nSize
),
287 pTempIndices
[nTempIndices
] = nPos
; // default constructed for cpp call
288 // will be released at reconversion
289 ppTempParamTypeDescr
[nTempIndices
++] = pParamTypeDescr
;
292 else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr
))
294 uno_copyAndConvertData(
295 pCppArgs
[nPos
] = alloca( pParamTypeDescr
->nSize
),
296 pUnoArgs
[nPos
], pParamTypeDescr
, pThis
->getBridge()->getUno2Cpp() );
298 pTempIndices
[nTempIndices
] = nPos
; // has to be reconverted
299 // will be released at reconversion
300 ppTempParamTypeDescr
[nTempIndices
++] = pParamTypeDescr
;
304 pCppArgs
[nPos
] = pUnoArgs
[nPos
];
306 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
308 INSERT_INT32( &(pCppArgs
[nPos
]), nRegs
, pGPR
, pStack
, bOverflow
);
316 pAdjustedThisPtr
, aVtableSlot
.index
,
317 pCppReturn
, pReturnTypeDescr
, bRegisterReturn
,
319 (pStack
- pStackStart
), pGPR
, pFPR
);
320 } catch (css::uno::Exception
&) {
322 } catch (std::exception
& e
) {
323 throw css::uno::RuntimeException(
324 "C++ code threw " + o3tl::runtimeToOUString(typeid(e
).name()) + ": "
325 + o3tl::runtimeToOUString(e
.what()));
327 throw css::uno::RuntimeException("C++ code threw unknown exception");
330 // NO exception occurred...
333 // reconvert temporary params
334 for ( ; nTempIndices
--; )
336 sal_Int32 nIndex
= pTempIndices
[nTempIndices
];
337 typelib_TypeDescription
* pParamTypeDescr
= ppTempParamTypeDescr
[nTempIndices
];
339 if (pParams
[nIndex
].bIn
)
341 if (pParams
[nIndex
].bOut
) // inout
343 uno_destructData( pUnoArgs
[nIndex
], pParamTypeDescr
, 0 ); // destroy uno value
344 uno_copyAndConvertData( pUnoArgs
[nIndex
], pCppArgs
[nIndex
], pParamTypeDescr
,
345 pThis
->getBridge()->getCpp2Uno() );
350 uno_copyAndConvertData( pUnoArgs
[nIndex
], pCppArgs
[nIndex
], pParamTypeDescr
,
351 pThis
->getBridge()->getCpp2Uno() );
353 // destroy temp cpp param => cpp: every param was constructed
354 uno_destructData( pCppArgs
[nIndex
], pParamTypeDescr
, cpp_release
);
356 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
359 if (pCppReturn
&& pUnoReturn
!= pCppReturn
)
361 uno_copyAndConvertData( pUnoReturn
, pCppReturn
, pReturnTypeDescr
,
362 pThis
->getBridge()->getCpp2Uno() );
363 uno_destructData( pCppReturn
, pReturnTypeDescr
, cpp_release
);
368 // fill uno exception
369 CPPU_CURRENT_NAMESPACE::fillUnoException(*ppUnoExc
, pThis
->getBridge()->getCpp2Uno());
372 for ( ; nTempIndices
--; )
374 sal_Int32 nIndex
= pTempIndices
[nTempIndices
];
375 // destroy temp cpp param => cpp: every param was constructed
376 uno_destructData( pCppArgs
[nIndex
], ppTempParamTypeDescr
[nTempIndices
], cpp_release
);
377 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr
[nTempIndices
] );
381 if (pReturnTypeDescr
)
382 TYPELIB_DANGER_RELEASE( pReturnTypeDescr
);
387 namespace bridges::cpp_uno::shared
{
389 void unoInterfaceProxyDispatch(
390 uno_Interface
* pUnoI
, const typelib_TypeDescription
* pMemberDescr
,
391 void * pReturn
, void * pArgs
[], uno_Any
** ppException
)
394 bridges::cpp_uno::shared::UnoInterfaceProxy
* pThis
395 = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy
* >(pUnoI
);
396 #if OSL_DEBUG_LEVEL > 0
397 typelib_InterfaceTypeDescription
* pTypeDescr
= pThis
->pTypeDescr
;
400 switch (pMemberDescr
->eTypeClass
)
402 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
404 #if OSL_DEBUG_LEVEL > 0
405 // determine vtable call index
406 sal_Int32 nMemberPos
= ((typelib_InterfaceMemberTypeDescription
*)pMemberDescr
)->nPosition
;
407 assert(nMemberPos
< pTypeDescr
->nAllMembers
);
410 VtableSlot
aVtableSlot(
412 reinterpret_cast<typelib_InterfaceAttributeTypeDescription
const *>
417 // dependent dispatch
420 ((typelib_InterfaceAttributeTypeDescription
*)pMemberDescr
)->pAttributeTypeRef
,
422 pReturn
, pArgs
, ppException
);
427 typelib_MethodParameter aParam
;
429 ((typelib_InterfaceAttributeTypeDescription
*)pMemberDescr
)->pAttributeTypeRef
;
430 aParam
.bIn
= sal_True
;
431 aParam
.bOut
= sal_False
;
433 typelib_TypeDescriptionReference
* pReturnTypeRef
= 0;
434 OUString
aVoidName("void");
435 typelib_typedescriptionreference_new(
436 &pReturnTypeRef
, typelib_TypeClass_VOID
, aVoidName
.pData
);
438 // dependent dispatch
439 aVtableSlot
.index
+= 1;
441 pThis
, aVtableSlot
, // get, then set method
444 pReturn
, pArgs
, ppException
);
446 typelib_typedescriptionreference_release( pReturnTypeRef
);
451 case typelib_TypeClass_INTERFACE_METHOD
:
453 #if OSL_DEBUG_LEVEL > 0
454 // determine vtable call index
455 sal_Int32 nMemberPos
= ((typelib_InterfaceMemberTypeDescription
*)pMemberDescr
)->nPosition
;
456 assert(nMemberPos
< pTypeDescr
->nAllMembers
);
459 VtableSlot
aVtableSlot(
461 reinterpret_cast<typelib_InterfaceMethodTypeDescription
const *>
464 switch (aVtableSlot
.index
)
467 case 1: // acquire uno interface
468 (*pUnoI
->acquire
)( pUnoI
);
471 case 2: // release uno interface
472 (*pUnoI
->release
)( pUnoI
);
475 case 0: // queryInterface() opt
477 typelib_TypeDescription
* pTD
= 0;
478 TYPELIB_DANGER_GET( &pTD
, reinterpret_cast< Type
* >( pArgs
[0] )->getTypeLibType() );
481 uno_Interface
* pInterface
= 0;
482 (*pThis
->getBridge()->getUnoEnv()->getRegisteredInterface
)(
483 pThis
->getBridge()->getUnoEnv(),
484 (void **)&pInterface
, pThis
->oid
.pData
, (typelib_InterfaceTypeDescription
*)pTD
);
489 reinterpret_cast< uno_Any
* >( pReturn
),
490 &pInterface
, pTD
, 0 );
491 (*pInterface
->release
)( pInterface
);
492 TYPELIB_DANGER_RELEASE( pTD
);
497 TYPELIB_DANGER_RELEASE( pTD
);
499 } // else perform queryInterface()
501 // dependent dispatch
504 ((typelib_InterfaceMethodTypeDescription
*)pMemberDescr
)->pReturnTypeRef
,
505 ((typelib_InterfaceMethodTypeDescription
*)pMemberDescr
)->nParams
,
506 ((typelib_InterfaceMethodTypeDescription
*)pMemberDescr
)->pParams
,
507 pReturn
, pArgs
, ppException
);
513 ::com::sun::star::uno::RuntimeException
aExc(
514 "illegal member type description!",
515 ::com::sun::star::uno::Reference
< ::com::sun::star::uno::XInterface
>() );
517 Type
const & rExcType
= cppu::UnoType
<decltype(aExc
)>::get();
518 // binary identical null reference
519 ::uno_type_any_construct( *ppException
, &aExc
, rExcType
.getTypeLibType(), 0 );
526 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */