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/config.h>
27 #include <com/sun/star/uno/Exception.hpp>
28 #include <com/sun/star/uno/RuntimeException.hpp>
29 #include <com/sun/star/uno/genfunc.hxx>
30 #include <o3tl/runtimetooustring.hxx>
35 #include "unointerfaceproxy.hxx"
36 #include "vtables.hxx"
45 #define INSERT_FLOAT_DOUBLE( pSV, nr, pFPR, pDS ) \
46 if ( nr < MAX_FP_REGS ) \
47 pFPR[nr++] = *reinterpret_cast<double *>( pSV ); \
49 *pDS++ = *reinterpret_cast<sal_uInt64 *>( pSV ); // verbatim!
51 #define INSERT_INT64( pSV, nr, pGPR, pDS ) \
52 if ( nr < MAX_GP_REGS ) \
53 pGPR[nr++] = *reinterpret_cast<sal_Int64 *>( pSV ); \
55 *pDS++ = *reinterpret_cast<sal_Int64 *>( pSV );
57 #define INSERT_INT32( pSV, nr, pGPR, pDS ) \
58 if ( nr < MAX_GP_REGS ) \
59 pGPR[nr++] = *reinterpret_cast<sal_Int32 *>( pSV ); \
61 *pDS++ = *reinterpret_cast<sal_Int32 *>( pSV );
63 #define INSERT_INT16( pSV, nr, pGPR, pDS ) \
64 if ( nr < MAX_GP_REGS ) \
65 pGPR[nr++] = *reinterpret_cast<sal_Int16 *>( pSV ); \
67 *pDS++ = *reinterpret_cast<sal_Int16 *>( pSV );
69 #define INSERT_UINT16( pSV, nr, pGPR, pDS ) \
70 if ( nr < MAX_GP_REGS ) \
71 pGPR[nr++] = *reinterpret_cast<sal_uInt16 *>( pSV ); \
73 *pDS++ = *reinterpret_cast<sal_uInt16 *>( pSV );
75 #define INSERT_INT8( pSV, nr, pGPR, pDS ) \
76 if ( nr < MAX_GP_REGS ) \
77 pGPR[nr++] = *reinterpret_cast<sal_Int8 *>( pSV ); \
79 *pDS++ = *reinterpret_cast<sal_Int8 *>( pSV );
81 using namespace ::com::sun::star::uno
;
86 bool isReturnInFPR(const typelib_TypeDescription
* pTypeDescr
, sal_uInt32
& nSize
)
88 const typelib_CompoundTypeDescription
*p
=
89 reinterpret_cast<const typelib_CompoundTypeDescription
*>( pTypeDescr
);
91 for (sal_Int32 i
= 0; i
< p
->nMembers
; ++i
)
93 typelib_TypeDescriptionReference
*pTypeInStruct
= p
->ppTypeRefs
[ i
];
95 switch (pTypeInStruct
->eTypeClass
)
97 case typelib_TypeClass_STRUCT
:
98 case typelib_TypeClass_EXCEPTION
:
100 typelib_TypeDescription
* t
= 0;
101 TYPELIB_DANGER_GET(&t
, pTypeInStruct
);
102 bool isFPR
= isReturnInFPR(t
, nSize
);
103 TYPELIB_DANGER_RELEASE(t
);
108 case typelib_TypeClass_FLOAT
:
109 case typelib_TypeClass_DOUBLE
:
122 void fillReturn(const typelib_TypeDescription
* pTypeDescr
,
123 sal_Int64
* gret
, double * fret
, void * pRegisterReturn
)
125 sal_uInt32 nSize
= 0;
126 if (isReturnInFPR(pTypeDescr
, nSize
))
128 reinterpret_cast<double *>( pRegisterReturn
)[0] = fret
[0];
129 reinterpret_cast<double *>( pRegisterReturn
)[1] = fret
[1];
133 reinterpret_cast<sal_Int64
*>( pRegisterReturn
)[0] = gret
[0];
134 reinterpret_cast<sal_Int64
*>( pRegisterReturn
)[1] = gret
[1];
138 static void callVirtualMethod(
139 void * pAdjustedThisPtr
,
140 sal_Int32 nVtableIndex
,
141 void * pRegisterReturn
,
142 typelib_TypeDescriptionReference
* pReturnTypeRef
,
150 // Should not happen, but...
151 static_assert(MAX_GP_REGS
== MAX_FP_REGS
, "must be the same size");
152 if ( nREG
> MAX_GP_REGS
)
155 // Get pointer to method
156 sal_uInt64 pMethod
= *((sal_uInt64
*)pAdjustedThisPtr
);
157 pMethod
+= 8 * nVtableIndex
;
158 void *mfunc
= (void *) *((sal_uInt64
*)pMethod
);
160 fprintf(stderr
, "calling function %p\n", mfunc
);
163 // Load parameters to stack, if necessary
164 sal_uInt64
* pCallStack
= NULL
;
168 sal_uInt32 nStackBytes
= ( ( nStack
+ 1 ) >> 1 ) * 16;
169 pCallStack
= (sal_uInt64
*) __builtin_alloca( nStackBytes
);
170 std::memcpy( pCallStack
, pStack
, nStackBytes
);
178 // Fill the general purpose registers
179 "ld $4, 0(%[gpr]) \n\t"
180 "ld $5, 8(%[gpr]) \n\t"
181 "ld $6, 16(%[gpr]) \n\t"
182 "ld $7, 24(%[gpr]) \n\t"
183 "ld $8, 32(%[gpr]) \n\t"
184 "ld $9, 40(%[gpr]) \n\t"
185 "ld $10, 48(%[gpr]) \n\t"
186 "ld $11, 56(%[gpr]) \n\t"
187 // Fill the floating pointer registers
188 "ldc1 $f12, 0(%[fpr]) \n\t"
189 "ldc1 $f13, 8(%[fpr]) \n\t"
190 "ldc1 $f14, 16(%[fpr]) \n\t"
191 "ldc1 $f15, 24(%[fpr]) \n\t"
192 "ldc1 $f16, 32(%[fpr]) \n\t"
193 "ldc1 $f17, 40(%[fpr]) \n\t"
194 "ldc1 $f18, 48(%[fpr]) \n\t"
195 "ldc1 $f19, 56(%[fpr]) \n\t"
198 // Fill the return values
199 "move %[gret1], $2 \n\t"
200 "move %[gret2], $3 \n\t"
201 "mov.d %[fret1], $f0 \n\t"
202 "mov.d %[fret2], $f2 \n\t"
204 :[gret1
]"=r"(gret
[0]), [gret2
]"=r"(gret
[1]),
205 [fret1
]"=f"(fret
[0]), [fret2
]"=f"(fret
[1])
206 :[gpr
]"r"(pGPR
), [fpr
]"r"(pFPR
), [mfunc
]"c"(mfunc
),
207 [stack
]"m"(pCallStack
) // dummy input to prevent the compiler from optimizing the alloca out
208 :"$2", "$3", "$4", "$5", "$6", "$7", "$8",
209 "$9", "$10", "$11", "$31",
210 "$f0", "$f2", "$f12", "$f13", "$f14", "$f15",
211 "$f16", "$f17", "$f18", "$f19", "memory"
214 switch (pReturnTypeRef
->eTypeClass
)
216 case typelib_TypeClass_HYPER
:
217 case typelib_TypeClass_UNSIGNED_HYPER
:
218 case typelib_TypeClass_LONG
:
219 case typelib_TypeClass_UNSIGNED_LONG
:
220 case typelib_TypeClass_ENUM
:
221 case typelib_TypeClass_CHAR
:
222 case typelib_TypeClass_SHORT
:
223 case typelib_TypeClass_UNSIGNED_SHORT
:
224 case typelib_TypeClass_BOOLEAN
:
225 case typelib_TypeClass_BYTE
:
226 *reinterpret_cast<sal_Int64
*>( pRegisterReturn
) = gret
[0];
228 case typelib_TypeClass_FLOAT
:
229 case typelib_TypeClass_DOUBLE
:
230 *reinterpret_cast<double *>( pRegisterReturn
) = fret
[0];
232 case typelib_TypeClass_STRUCT
:
233 case typelib_TypeClass_EXCEPTION
:
235 sal_Int32
const nRetSize
= pReturnTypeRef
->pType
->nSize
;
236 if (bSimpleReturn
&& nRetSize
<= 16 && nRetSize
> 0)
238 typelib_TypeDescription
* pTypeDescr
= 0;
239 TYPELIB_DANGER_GET( &pTypeDescr
, pReturnTypeRef
);
240 fillReturn(pTypeDescr
, gret
, fret
, pRegisterReturn
);
241 TYPELIB_DANGER_RELEASE( pTypeDescr
);
247 fprintf(stderr
,"unhandled return type %u\n", pReturnTypeRef
->eTypeClass
);
254 static void cpp_call(
255 bridges::cpp_uno::shared::UnoInterfaceProxy
* pThis
,
256 bridges::cpp_uno::shared::VtableSlot aVtableSlot
,
257 typelib_TypeDescriptionReference
* pReturnTypeRef
,
258 sal_Int32 nParams
, typelib_MethodParameter
* pParams
,
259 void * pUnoReturn
, void * pUnoArgs
[], uno_Any
** ppUnoExc
)
261 // max space for: [complex ret ptr], values|ptr ...
262 sal_uInt64
*pStack
= (sal_uInt64
*)__builtin_alloca( ((nParams
+3) * sizeof(sal_Int64
)) );
263 sal_uInt64
*pStackStart
= pStack
;
265 sal_uInt64 pGPR
[MAX_GP_REGS
];
266 double pFPR
[MAX_FP_REGS
];
270 fprintf(stderr
, "in cpp_call\n");
274 typelib_TypeDescription
* pReturnTypeDescr
= 0;
275 TYPELIB_DANGER_GET( &pReturnTypeDescr
, pReturnTypeRef
);
276 assert(pReturnTypeDescr
);
278 void * pCppReturn
= 0; // if != 0 && != pUnoReturn, needs reconversion
280 bool bSimpleReturn
= true;
281 if (pReturnTypeDescr
)
283 if ( CPPU_CURRENT_NAMESPACE::return_in_hidden_param( pReturnTypeRef
) )
285 bSimpleReturn
= false;
286 // complex return via ptr
287 pCppReturn
= bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr
)?
288 __builtin_alloca( pReturnTypeDescr
->nSize
) : pUnoReturn
;
289 INSERT_INT64( &pCppReturn
, nREG
, pGPR
, pStack
);
293 pCppReturn
= pUnoReturn
; // direct way for simple types
298 void* pAdjustedThisPtr
= reinterpret_cast< void **>( pThis
->getCppI() ) + aVtableSlot
.offset
;
299 INSERT_INT64( &pAdjustedThisPtr
, nREG
, pGPR
, pStack
);
302 void ** pCppArgs
= (void **)alloca( 3 * sizeof(void *) * nParams
);
303 // indices of values this have to be converted (interface conversion cpp<=>uno)
304 sal_Int32
* pTempIndices
= (sal_Int32
*)(pCppArgs
+ nParams
);
305 // type descriptions for reconversions
306 typelib_TypeDescription
** ppTempParamTypeDescr
= (typelib_TypeDescription
**)(pCppArgs
+ (2 * nParams
));
308 sal_Int32 nTempIndices
= 0;
310 for ( sal_Int32 nPos
= 0; nPos
< nParams
; ++nPos
)
312 const typelib_MethodParameter
& rParam
= pParams
[nPos
];
313 typelib_TypeDescription
* pParamTypeDescr
= 0;
314 TYPELIB_DANGER_GET( &pParamTypeDescr
, rParam
.pTypeRef
);
316 if (!rParam
.bOut
&& bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr
))
318 uno_copyAndConvertData( pCppArgs
[nPos
] = alloca( 8 ), pUnoArgs
[nPos
], pParamTypeDescr
,
319 pThis
->getBridge()->getUno2Cpp() );
321 switch (pParamTypeDescr
->eTypeClass
)
323 case typelib_TypeClass_LONG
:
324 case typelib_TypeClass_UNSIGNED_LONG
:
325 case typelib_TypeClass_ENUM
:
326 INSERT_INT32( pCppArgs
[nPos
], nREG
, pGPR
, pStack
);
328 case typelib_TypeClass_CHAR
:
329 case typelib_TypeClass_SHORT
:
330 INSERT_INT16( pCppArgs
[nPos
], nREG
, pGPR
, pStack
);
332 case typelib_TypeClass_UNSIGNED_SHORT
:
333 INSERT_UINT16( pCppArgs
[nPos
], nREG
, pGPR
, pStack
);
335 case typelib_TypeClass_BOOLEAN
:
336 case typelib_TypeClass_BYTE
:
337 INSERT_INT8( pCppArgs
[nPos
], nREG
, pGPR
, pStack
);
339 case typelib_TypeClass_FLOAT
:
340 case typelib_TypeClass_DOUBLE
:
341 INSERT_FLOAT_DOUBLE( pCppArgs
[nPos
], nREG
, pFPR
, pStack
);
343 case typelib_TypeClass_HYPER
:
344 case typelib_TypeClass_UNSIGNED_HYPER
:
345 INSERT_INT64( pCppArgs
[nPos
], nREG
, pGPR
, pStack
);
352 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
354 else // ptr to complex value | ref
356 if (! rParam
.bIn
) // is pure out
358 // cpp out is constructed mem, uno out is not!
360 pCppArgs
[nPos
] = alloca( pParamTypeDescr
->nSize
),
362 pTempIndices
[nTempIndices
] = nPos
; // default constructed for cpp call
363 // will be released at reconversion
364 ppTempParamTypeDescr
[nTempIndices
++] = pParamTypeDescr
;
367 else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr
))
369 uno_copyAndConvertData(
370 pCppArgs
[nPos
] = alloca( pParamTypeDescr
->nSize
),
371 pUnoArgs
[nPos
], pParamTypeDescr
, pThis
->getBridge()->getUno2Cpp() );
373 pTempIndices
[nTempIndices
] = nPos
; // has to be reconverted
374 // will be released at reconversion
375 ppTempParamTypeDescr
[nTempIndices
++] = pParamTypeDescr
;
379 pCppArgs
[nPos
] = pUnoArgs
[nPos
];
381 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
383 INSERT_INT64( &(pCppArgs
[nPos
]), nREG
, pGPR
, pStack
);
391 pAdjustedThisPtr
, aVtableSlot
.index
,
392 pCppReturn
, pReturnTypeRef
, bSimpleReturn
,
393 pStackStart
, ( pStack
- pStackStart
),
395 } catch (css::uno::Exception
&) {
397 } catch (std::exception
& e
) {
398 throw css::uno::RuntimeException(
399 "C++ code threw " + o3tl::runtimeToOUString(typeid(e
).name()) + ": "
400 + o3tl::runtimeToOUString(e
.what()));
402 throw css::uno::RuntimeException("C++ code threw unknown exception");
404 // NO exception occurred...
407 // reconvert temporary params
408 for ( ; nTempIndices
--; )
410 sal_Int32 nIndex
= pTempIndices
[nTempIndices
];
411 typelib_TypeDescription
* pParamTypeDescr
= ppTempParamTypeDescr
[nTempIndices
];
413 if (pParams
[nIndex
].bIn
)
415 if (pParams
[nIndex
].bOut
) // inout
417 uno_destructData( pUnoArgs
[nIndex
], pParamTypeDescr
, 0 ); // destroy uno value
418 uno_copyAndConvertData( pUnoArgs
[nIndex
], pCppArgs
[nIndex
], pParamTypeDescr
,
419 pThis
->getBridge()->getCpp2Uno() );
424 uno_copyAndConvertData( pUnoArgs
[nIndex
], pCppArgs
[nIndex
], pParamTypeDescr
,
425 pThis
->getBridge()->getCpp2Uno() );
427 // destroy temp cpp param => cpp: every param was constructed
428 uno_destructData( pCppArgs
[nIndex
], pParamTypeDescr
, cpp_release
);
430 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
433 if (pCppReturn
&& pUnoReturn
!= pCppReturn
)
435 uno_copyAndConvertData( pUnoReturn
, pCppReturn
, pReturnTypeDescr
,
436 pThis
->getBridge()->getCpp2Uno() );
437 uno_destructData( pCppReturn
, pReturnTypeDescr
, cpp_release
);
442 // fill uno exception
443 CPPU_CURRENT_NAMESPACE::fillUnoException(*ppUnoExc
, pThis
->getBridge()->getCpp2Uno());
446 for ( ; nTempIndices
--; )
448 sal_Int32 nIndex
= pTempIndices
[nTempIndices
];
449 // destroy temp cpp param => cpp: every param was constructed
450 uno_destructData( pCppArgs
[nIndex
], ppTempParamTypeDescr
[nTempIndices
], cpp_release
);
451 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr
[nTempIndices
] );
454 if (pReturnTypeDescr
)
455 TYPELIB_DANGER_RELEASE( pReturnTypeDescr
);
462 namespace bridges
{ namespace cpp_uno
{ namespace shared
{
464 void unoInterfaceProxyDispatch(
465 uno_Interface
* pUnoI
, const typelib_TypeDescription
* pMemberDescr
,
466 void * pReturn
, void * pArgs
[], uno_Any
** ppException
)
469 bridges::cpp_uno::shared::UnoInterfaceProxy
* pThis
470 = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy
*> (pUnoI
);
471 //typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
474 fprintf(stderr
, "in dispatch\n");
477 switch (pMemberDescr
->eTypeClass
)
479 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
482 VtableSlot
aVtableSlot(
485 typelib_InterfaceAttributeTypeDescription
const * >(
490 // dependent dispatch
493 ((typelib_InterfaceAttributeTypeDescription
*)pMemberDescr
)->pAttributeTypeRef
,
495 pReturn
, pArgs
, ppException
);
500 typelib_MethodParameter aParam
;
502 ((typelib_InterfaceAttributeTypeDescription
*)pMemberDescr
)->pAttributeTypeRef
;
503 aParam
.bIn
= sal_True
;
504 aParam
.bOut
= sal_False
;
506 typelib_TypeDescriptionReference
* pReturnTypeRef
= 0;
507 OUString
aVoidName("void");
508 typelib_typedescriptionreference_new(
509 &pReturnTypeRef
, typelib_TypeClass_VOID
, aVoidName
.pData
);
511 // dependent dispatch
512 aVtableSlot
.index
+= 1; //get then set method
517 pReturn
, pArgs
, ppException
);
519 typelib_typedescriptionreference_release( pReturnTypeRef
);
524 case typelib_TypeClass_INTERFACE_METHOD
:
527 VtableSlot
aVtableSlot(
530 typelib_InterfaceMethodTypeDescription
const * >(
532 switch (aVtableSlot
.index
)
535 case 1: // acquire uno interface
536 (*pUnoI
->acquire
)( pUnoI
);
539 case 2: // release uno interface
540 (*pUnoI
->release
)( pUnoI
);
543 case 0: // queryInterface() opt
545 typelib_TypeDescription
* pTD
= 0;
546 TYPELIB_DANGER_GET( &pTD
, reinterpret_cast< Type
* >( pArgs
[0] )->getTypeLibType() );
549 uno_Interface
* pInterface
= 0;
550 (*pThis
->pBridge
->getUnoEnv()->getRegisteredInterface
)(pThis
->pBridge
->getUnoEnv(),
551 (void **)&pInterface
, pThis
->oid
.pData
,
552 (typelib_InterfaceTypeDescription
*)pTD
);
557 reinterpret_cast< uno_Any
* >( pReturn
),
558 &pInterface
, pTD
, 0 );
559 (*pInterface
->release
)( pInterface
);
560 TYPELIB_DANGER_RELEASE( pTD
);
564 TYPELIB_DANGER_RELEASE( pTD
);
566 } // else perform queryInterface()
568 // dependent dispatch
571 ((typelib_InterfaceMethodTypeDescription
*)pMemberDescr
)->pReturnTypeRef
,
572 ((typelib_InterfaceMethodTypeDescription
*)pMemberDescr
)->nParams
,
573 ((typelib_InterfaceMethodTypeDescription
*)pMemberDescr
)->pParams
,
574 pReturn
, pArgs
, ppException
);
580 ::com::sun::star::uno::RuntimeException
aExc(
581 "illegal member type description!",
582 ::com::sun::star::uno::Reference
< ::com::sun::star::uno::XInterface
>() );
584 Type
const & rExcType
= cppu::UnoType
<decltype(aExc
)>::get();
585 // binary identical null reference
586 ::uno_type_any_construct( *ppException
, &aExc
, rExcType
.getTypeLibType(), 0 );
592 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */