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>
26 #include <com/sun/star/uno/Exception.hpp>
27 #include <com/sun/star/uno/RuntimeException.hpp>
28 #include <com/sun/star/uno/genfunc.hxx>
29 #include <o3tl/runtimetooustring.hxx>
34 #include "unointerfaceproxy.hxx"
35 #include "vtables.hxx"
40 using namespace ::com::sun::star::uno
;
46 static void callVirtualMethod(
47 void * pAdjustedThisPtr
,
48 sal_Int32 nVtableIndex
,
49 void * pRegisterReturn
,
50 typelib_TypeClass eReturnType
,
52 sal_Int32
* pStackLongs
,
53 sal_Int32 nStackLongs
)
56 // parameter list is mixed list of * and values
57 // reference parameters are pointers
59 // the basic idea here is to use gpr[8] as a storage area for
60 // the future values of registers r3 to r10 needed for the call,
61 // and similarly fpr[8] as a storage area for the future values
62 // of floating point registers f1 to f8
64 unsigned long * mfunc
; // actual function to be invoked
65 int gpr
[8]; // storage for gpregisters, map to r3-r10
66 int off
; // offset used to find function
68 double fpr
[8]; // storage for fpregisters, map to f1-f8
69 int f
; // number of fprs mapped so far
70 double dret
; // temporary function return values
72 int n
; // number of gprs mapped so far
73 long *p
; // pointer to parameter overflow area
74 int c
; // character of parameter type being decoded
77 // Because of the Power PC calling conventions we could be passing
78 // parameters in both register types and on the stack. To create the
79 // stack parameter area we need we now simply allocate local
80 // variable storage param[] that is at least the size of the parameter stack
81 // (more than enough space) which we can overwrite the parameters into.
83 // Note: This keeps us from having to decode the signature twice and
84 // prevents problems with later local variables.
86 // Note: could require up to 2*nStackLongs words of parameter stack area
87 // if the call has many float parameters (i.e. floats take up only 1
88 // word on the stack but double takes 2 words in parameter area in the
91 // Update! Floats on the outgoing parameter stack only take up 1 word
92 // (stfs is used) which is not correct according to the ABI but we
93 // will match what the compiler does until this is figured out
95 // this grows the current stack to the appropriate size
96 // and sets the outgoing stack pointer p to the right place
97 __asm__
__volatile__ (
98 "rlwinm %0,%0,3,3,28\n\t"
100 "rlwinm %0,%0,0,4,28\n\t"
104 : : "r" (nStackLongs
) : "0" );
106 __asm__
__volatile__ ( "addi %0,1,8" : "=r" (p
) : );
109 // if (! pAdjustedThisPtr ) dummy_can_throw_anything("xxx"); // address something
112 // now begin to load the C++ function arguments into storage
118 // now we need to parse the entire signature string */
119 // until we get the END indicator */
121 // treat complex return pointer like any other parameter
124 /* Let's figure out what is really going on here*/
125 fprintf(stderr
,"callVirtualMethod parameters string is %s\n",pPT
);
127 long * q
= (long *)pStackLongs
;
129 fprintf(stderr
,"uno stack is: %x\n",*q
);
135 /* parse the argument list up to the ending ) */
136 while (*pPT
!= 'X') {
139 case 'D': /* type is double */
142 fpr
[f
++] = *((double *)pStackLongs
); /* store in register */
147 gpr
[n
++] = *pStackLongs
;
148 gpr
[n
++] = *(pStackLongs
+1);
153 *p
++ = *pStackLongs
; /* or on the parameter stack */
154 *p
++ = *(pStackLongs
+ 1);
159 case 'F': /* type is float */
160 /* this assumes that floats are stored as 1 32 bit word on param
161 stack and that if passed in parameter stack to C, should be
164 Whoops: the abi is not actually followed by gcc, need to
165 store floats as a *single* word on outgoing parameter stack
166 to match what gcc actually does
170 fpr
[f
++] = *((float *)pStackLongs
);
173 gpr
[n
++] = *pStackLongs
;
176 #if 0 /* if abi were followed */
179 *((double *)p
) = *((float *)pStackLongs
);
182 *((float *)p
) = *((float *)pStackLongs
);
189 case 'H': /* type is long long */
190 if (n
& 1) n
++; /* note even elements gpr[] will map to
193 gpr
[n
++] = *pStackLongs
;
194 gpr
[n
++] = *(pStackLongs
+1);
199 *p
++ = *(pStackLongs
+1);
206 gpr
[n
++] = *((unsigned short*)pStackLongs
);
208 *p
++ = *((unsigned short *)pStackLongs
);
215 gpr
[n
++] = *((char *)pStackLongs
);
217 *p
++ = *((char *)pStackLongs
);
224 gpr
[n
++] = *pStackLongs
;
234 /* figure out the address of the function we need to invoke */
236 off
= off
* 4; // 4 bytes per slot
237 mfunc
= *((unsigned long **)pAdjustedThisPtr
); // get the address of the vtable
238 mfunc
= (unsigned long *)((char *)mfunc
+ off
); // get the address from the vtable entry at offset
239 mfunc
= *((unsigned long **)mfunc
); // the function is stored at the address
240 typedef void (*FunctionCall
)(sal_uInt32
, sal_uInt32
, sal_uInt32
, sal_uInt32
, sal_uInt32
, sal_uInt32
, sal_uInt32
, sal_uInt32
);
241 FunctionCall ptr
= (FunctionCall
)mfunc
;
243 /* Set up the machine registers and invoke the function */
245 __asm__
__volatile__ (
263 : : "r" (gpr
), "r" (fpr
)
267 : "0", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"
270 // tell gcc that r3 to r10 are not available to it for doing the TOC and exception munge on the func call
271 register sal_uInt32 r3
__asm__("r3");
272 register sal_uInt32 r4
__asm__("r4");
273 register sal_uInt32 r5
__asm__("r5");
274 register sal_uInt32 r6
__asm__("r6");
275 register sal_uInt32 r7
__asm__("r7");
276 register sal_uInt32 r8
__asm__("r8");
277 register sal_uInt32 r9
__asm__("r9");
278 register sal_uInt32 r10
__asm__("r10");
280 (*ptr
)(r3
, r4
, r5
, r6
, r7
, r8
, r9
, r10
);
282 __asm__
__volatile__ (
287 : "=r" (iret
), "=r" (iret2
), "=f" (dret
)
289 : "=r" (iret
), "=r" (iret2
)
293 switch( eReturnType
)
295 case typelib_TypeClass_HYPER
:
296 case typelib_TypeClass_UNSIGNED_HYPER
:
297 ((long*)pRegisterReturn
)[0] = iret
;
298 ((long*)pRegisterReturn
)[1] = iret2
;
299 case typelib_TypeClass_LONG
:
300 case typelib_TypeClass_UNSIGNED_LONG
:
301 case typelib_TypeClass_ENUM
:
302 ((long*)pRegisterReturn
)[0] = iret
;
304 case typelib_TypeClass_CHAR
:
305 case typelib_TypeClass_SHORT
:
306 case typelib_TypeClass_UNSIGNED_SHORT
:
307 *(unsigned short*)pRegisterReturn
= (unsigned short)iret
;
309 case typelib_TypeClass_BOOLEAN
:
310 case typelib_TypeClass_BYTE
:
311 *(unsigned char*)pRegisterReturn
= (unsigned char)iret
;
313 case typelib_TypeClass_FLOAT
:
315 *(float*)pRegisterReturn
= (float)dret
;
317 ((unsigned int*)pRegisterReturn
)[0] = iret
;
320 case typelib_TypeClass_DOUBLE
:
322 *(double*)pRegisterReturn
= dret
;
324 ((unsigned int*)pRegisterReturn
)[0] = iret
;
325 ((unsigned int*)pRegisterReturn
)[1] = iret2
;
334 static void cpp_call(
335 bridges::cpp_uno::shared::UnoInterfaceProxy
* pThis
,
336 bridges::cpp_uno::shared::VtableSlot aVtableSlot
,
337 typelib_TypeDescriptionReference
* pReturnTypeRef
,
338 sal_Int32 nParams
, typelib_MethodParameter
* pParams
,
339 void * pUnoReturn
, void * pUnoArgs
[], uno_Any
** ppUnoExc
)
341 // max space for: [complex ret ptr], values|ptr ...
343 (char *)alloca( sizeof(sal_Int32
) + ((nParams
+2) * sizeof(sal_Int64
)) );
344 char * pCppStackStart
= pCppStack
;
346 // need to know parameter types for callVirtualMethod so generate a signature string
347 char * pParamType
= (char *) alloca(nParams
+2);
348 char * pPT
= pParamType
;
351 typelib_TypeDescription
* pReturnTypeDescr
= 0;
352 TYPELIB_DANGER_GET( &pReturnTypeDescr
, pReturnTypeRef
);
353 // assert(pReturnTypeDescr);
355 void * pCppReturn
= 0; // if != 0 && != pUnoReturn, needs reconversion
357 if (pReturnTypeDescr
)
359 if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr
))
361 pCppReturn
= pUnoReturn
; // direct way for simple types
365 // complex return via ptr
366 pCppReturn
= *(void **)pCppStack
=
367 (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr
)
368 ? alloca( pReturnTypeDescr
->nSize
): pUnoReturn
); // direct way
369 *pPT
++ = 'I'; //signify that a complex return type on stack
370 pCppStack
+= sizeof(void *);
374 void* pAdjustedThisPtr
= reinterpret_cast< void **>(pThis
->getCppI()) + aVtableSlot
.offset
;
375 *(void**)pCppStack
= pAdjustedThisPtr
;
376 pCppStack
+= sizeof( void* );
380 // static_assert(sizeof(void *) == sizeof(sal_Int32), "### unexpected size!");
382 void ** pCppArgs
= (void **)alloca( 3 * sizeof(void *) * nParams
);
383 // indices of values this have to be converted (interface conversion cpp<=>uno)
384 sal_Int32
* pTempIndices
= (sal_Int32
*)(pCppArgs
+ nParams
);
385 // type descriptions for reconversions
386 typelib_TypeDescription
** ppTempParamTypeDescr
= (typelib_TypeDescription
**)(pCppArgs
+ (2 * nParams
));
388 sal_Int32 nTempIndices
= 0;
390 for ( sal_Int32 nPos
= 0; nPos
< nParams
; ++nPos
)
392 const typelib_MethodParameter
& rParam
= pParams
[nPos
];
393 typelib_TypeDescription
* pParamTypeDescr
= 0;
394 TYPELIB_DANGER_GET( &pParamTypeDescr
, rParam
.pTypeRef
);
396 if (!rParam
.bOut
&& bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr
))
398 uno_copyAndConvertData( pCppArgs
[nPos
] = pCppStack
, pUnoArgs
[nPos
], pParamTypeDescr
,
399 pThis
->getBridge()->getUno2Cpp() );
401 switch (pParamTypeDescr
->eTypeClass
)
404 // we need to know type of each param so that we know whether to use
405 // gpr or fpr to pass in parameters:
406 // Key: I - int, long, pointer, etc means pass in gpr
407 // B - byte value passed in gpr
408 // S - short value passed in gpr
409 // F - float value pass in fpr
410 // D - double value pass in fpr
411 // H - long long int pass in proper pairs of gpr (3,4) (5,6), etc
412 // X - indicates end of parameter description string
414 case typelib_TypeClass_LONG
:
415 case typelib_TypeClass_UNSIGNED_LONG
:
416 case typelib_TypeClass_ENUM
:
419 case typelib_TypeClass_SHORT
:
420 case typelib_TypeClass_CHAR
:
421 case typelib_TypeClass_UNSIGNED_SHORT
:
424 case typelib_TypeClass_BOOLEAN
:
425 case typelib_TypeClass_BYTE
:
428 case typelib_TypeClass_FLOAT
:
431 case typelib_TypeClass_DOUBLE
:
433 pCppStack
+= sizeof(sal_Int32
); // extra long
435 case typelib_TypeClass_HYPER
:
436 case typelib_TypeClass_UNSIGNED_HYPER
:
438 pCppStack
+= sizeof(sal_Int32
); // extra long
444 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
446 else // ptr to complex value | ref
448 if (! rParam
.bIn
) // is pure out
450 // cpp out is constructed mem, uno out is not!
452 *(void **)pCppStack
= pCppArgs
[nPos
] = alloca( pParamTypeDescr
->nSize
),
454 pTempIndices
[nTempIndices
] = nPos
; // default constructed for cpp call
455 // will be released at reconversion
456 ppTempParamTypeDescr
[nTempIndices
++] = pParamTypeDescr
;
459 else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr
))
461 uno_copyAndConvertData(
462 *(void **)pCppStack
= pCppArgs
[nPos
] = alloca( pParamTypeDescr
->nSize
),
463 pUnoArgs
[nPos
], pParamTypeDescr
,
464 pThis
->getBridge()->getUno2Cpp() );
466 pTempIndices
[nTempIndices
] = nPos
; // has to be reconverted
467 // will be released at reconversion
468 ppTempParamTypeDescr
[nTempIndices
++] = pParamTypeDescr
;
472 *(void **)pCppStack
= pCppArgs
[nPos
] = pUnoArgs
[nPos
];
474 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
476 // KBH: FIXME: is this the right way to pass these
479 pCppStack
+= sizeof(sal_Int32
); // standard parameter length
482 // terminate the signature string
488 assert( !( (pCppStack
- pCppStackStart
) & 3) && "UNALIGNED STACK !!! (Please DO panic)");
491 pAdjustedThisPtr
, aVtableSlot
.index
,
492 pCppReturn
, pReturnTypeDescr
->eTypeClass
, pParamType
,
493 (sal_Int32
*)pCppStackStart
, (pCppStack
- pCppStackStart
) / sizeof(sal_Int32
) );
494 } catch (css::uno::Exception
&) {
496 } catch (std::exception
& e
) {
497 throw css::uno::RuntimeException(
498 "C++ code threw " + o3tl::runtimeToOUString(typeid(e
).name()) + ": "
499 + o3tl::runtimeToOUString(e
.what()));
501 throw css::uno::RuntimeException("C++ code threw unknown exception");
503 // NO exception occurred...
506 // reconvert temporary params
507 for ( ; nTempIndices
--; )
509 sal_Int32 nIndex
= pTempIndices
[nTempIndices
];
510 typelib_TypeDescription
* pParamTypeDescr
= ppTempParamTypeDescr
[nTempIndices
];
512 if (pParams
[nIndex
].bIn
)
514 if (pParams
[nIndex
].bOut
) // inout
516 uno_destructData( pUnoArgs
[nIndex
], pParamTypeDescr
, 0 ); // destroy uno value
517 uno_copyAndConvertData( pUnoArgs
[nIndex
], pCppArgs
[nIndex
], pParamTypeDescr
,
518 pThis
->getBridge()->getCpp2Uno() );
523 uno_copyAndConvertData( pUnoArgs
[nIndex
], pCppArgs
[nIndex
], pParamTypeDescr
,
524 pThis
->getBridge()->getCpp2Uno() );
526 // destroy temp cpp param => cpp: every param was constructed
527 uno_destructData( pCppArgs
[nIndex
], pParamTypeDescr
, cpp_release
);
529 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
532 if (pCppReturn
&& pUnoReturn
!= pCppReturn
)
534 uno_copyAndConvertData( pUnoReturn
, pCppReturn
, pReturnTypeDescr
,
535 pThis
->getBridge()->getCpp2Uno() );
536 uno_destructData( pCppReturn
, pReturnTypeDescr
, cpp_release
);
541 // fill uno exception
542 CPPU_CURRENT_NAMESPACE::fillUnoException(*ppUnoExc
, pThis
->getBridge()->getCpp2Uno());
545 for ( ; nTempIndices
--; )
547 sal_Int32 nIndex
= pTempIndices
[nTempIndices
];
548 // destroy temp cpp param => cpp: every param was constructed
549 uno_destructData( pCppArgs
[nIndex
], ppTempParamTypeDescr
[nTempIndices
], cpp_release
);
550 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr
[nTempIndices
] );
553 if (pReturnTypeDescr
)
554 TYPELIB_DANGER_RELEASE( pReturnTypeDescr
);
560 namespace bridges::cpp_uno::shared
{
562 void unoInterfaceProxyDispatch(
563 uno_Interface
* pUnoI
, const typelib_TypeDescription
* pMemberDescr
,
564 void * pReturn
, void * pArgs
[], uno_Any
** ppException
)
567 bridges::cpp_uno::shared::UnoInterfaceProxy
* pThis
568 = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy
*> (pUnoI
);
570 switch (pMemberDescr
->eTypeClass
)
572 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
575 VtableSlot
aVtableSlot(
578 typelib_InterfaceAttributeTypeDescription
const * >(
583 // dependent dispatch
586 ((typelib_InterfaceAttributeTypeDescription
*)pMemberDescr
)->pAttributeTypeRef
,
588 pReturn
, pArgs
, ppException
);
593 typelib_MethodParameter aParam
;
595 ((typelib_InterfaceAttributeTypeDescription
*)pMemberDescr
)->pAttributeTypeRef
;
596 aParam
.bIn
= sal_True
;
597 aParam
.bOut
= sal_False
;
599 typelib_TypeDescriptionReference
* pReturnTypeRef
= 0;
600 OUString
aVoidName("void");
601 typelib_typedescriptionreference_new(
602 &pReturnTypeRef
, typelib_TypeClass_VOID
, aVoidName
.pData
);
604 // dependent dispatch
605 aVtableSlot
.index
+= 1; //get then set method
610 pReturn
, pArgs
, ppException
);
612 typelib_typedescriptionreference_release( pReturnTypeRef
);
617 case typelib_TypeClass_INTERFACE_METHOD
:
620 VtableSlot
aVtableSlot(
623 typelib_InterfaceMethodTypeDescription
const * >(
625 switch (aVtableSlot
.index
)
628 case 1: // acquire uno interface
629 (*pUnoI
->acquire
)( pUnoI
);
632 case 2: // release uno interface
633 (*pUnoI
->release
)( pUnoI
);
636 case 0: // queryInterface() opt
638 typelib_TypeDescription
* pTD
= 0;
639 TYPELIB_DANGER_GET( &pTD
, reinterpret_cast< Type
* >( pArgs
[0] )->getTypeLibType() );
642 uno_Interface
* pInterface
= 0;
643 (*pThis
->pBridge
->getUnoEnv()->getRegisteredInterface
)(
644 pThis
->pBridge
->getUnoEnv(),
645 (void **)&pInterface
, pThis
->oid
.pData
, (typelib_InterfaceTypeDescription
*)pTD
);
650 reinterpret_cast< uno_Any
* >( pReturn
),
651 &pInterface
, pTD
, 0 );
652 (*pInterface
->release
)( pInterface
);
653 TYPELIB_DANGER_RELEASE( pTD
);
657 TYPELIB_DANGER_RELEASE( pTD
);
659 } // else perform queryInterface()
661 // dependent dispatch
664 ((typelib_InterfaceMethodTypeDescription
*)pMemberDescr
)->pReturnTypeRef
,
665 ((typelib_InterfaceMethodTypeDescription
*)pMemberDescr
)->nParams
,
666 ((typelib_InterfaceMethodTypeDescription
*)pMemberDescr
)->pParams
,
667 pReturn
, pArgs
, ppException
);
673 ::com::sun::star::uno::RuntimeException
aExc(
674 "illegal member type description!",
675 ::com::sun::star::uno::Reference
< ::com::sun::star::uno::XInterface
>() );
677 Type
const & rExcType
= cppu::UnoType
<decltype(aExc
)>::get();
678 // binary identical null reference
679 ::uno_type_any_construct( *ppException
, &aExc
, rExcType
.getTypeLibType(), 0 );
686 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */