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>
24 #include <com/sun/star/uno/RuntimeException.hpp>
25 #include <sal/log.hxx>
27 #include <typelib/typedescription.hxx>
29 #include "cppinterfaceproxy.hxx"
31 #include "vtablefactory.hxx"
36 extern "C" int codeSnippets
[];
37 const int nFunIndexes
= 8;
38 const int nVtableOffsets
= 4;
42 using namespace ::com::sun::star::uno
;
46 static typelib_TypeClass
cpp2uno_call(
47 bridges::cpp_uno::shared::CppInterfaceProxy
* pThis
,
48 const typelib_TypeDescription
* pMemberTypeDescr
,
49 typelib_TypeDescriptionReference
* pReturnTypeRef
,
51 typelib_MethodParameter
* pParams
,
53 sal_Int64
* pRegisterReturn
/* space for register return */ )
55 // pCallStack: x8, lr, d0..d7, x0..x7, rest of params originally on stack
56 char *pTopStack
= (char *)pCallStack
;
57 char *pFloatRegs
= pTopStack
+ 2;
58 char *pGPRegs
= pTopStack
+ (2+8)*8;
59 char *pStackedArgs
= pTopStack
+ (2+8+8)*8;
65 typelib_TypeDescription
* pReturnTypeDescr
= 0;
67 TYPELIB_DANGER_GET( &pReturnTypeDescr
, pReturnTypeRef
);
69 void * pUnoReturn
= 0;
70 // complex return ptr: if != 0 && != pUnoReturn, reconversion need
71 void * pCppReturn
= 0;
75 if (!arm::return_in_x8(pReturnTypeRef
))
76 pUnoReturn
= pRegisterReturn
; // direct way for simple types
77 else // complex return via x8
79 pCppReturn
= pCallStack
[0];
81 pUnoReturn
= (bridges::cpp_uno::shared::relatesToInterfaceType(
83 ? alloca( pReturnTypeDescr
->nSize
)
84 : pCppReturn
); // direct way
93 void ** pUnoArgs
= (void **)alloca( sizeof(void *) * nParams
);
94 void ** pCppArgs
= (void **)alloca( sizeof(void *) * nParams
);
96 // Indices of values this have to be converted (interface conversion
98 int * pTempIndices
= (sal_Int32
*)alloca( sizeof(int) * nParams
);
100 // Type descriptions for reconversions
101 typelib_TypeDescription
** ppTempParamTypeDescr
= (typelib_TypeDescription
**)alloca( sizeof(typelib_TypeDescription
*) * nParams
);
103 int nTempIndices
= 0;
105 for ( int nPos
= 0; nPos
< nParams
; ++nPos
)
107 const typelib_MethodParameter
& rParam
= pParams
[nPos
];
108 typelib_TypeDescription
* pParamTypeDescr
= 0;
109 TYPELIB_DANGER_GET( &pParamTypeDescr
, rParam
.pTypeRef
);
112 bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr
))
114 if (nFPR
< 8 && (pParamTypeDescr
->eTypeClass
== typelib_TypeClass_FLOAT
||
115 pParamTypeDescr
->eTypeClass
== typelib_TypeClass_DOUBLE
))
117 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = pFloatRegs
;
121 else if (pParamTypeDescr
->eTypeClass
== typelib_TypeClass_FLOAT
)
123 if ((pStackedArgs
- pTopStack
) % 4)
124 pStackedArgs
+= 4 - ((pStackedArgs
- pTopStack
) % 4);
125 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = pStackedArgs
;
128 else if (pParamTypeDescr
->eTypeClass
== typelib_TypeClass_DOUBLE
)
130 if ((pStackedArgs
- pTopStack
) % 8)
131 pStackedArgs
+= 8 - ((pStackedArgs
- pTopStack
) % 8);
132 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = pStackedArgs
;
137 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = pGPRegs
;
142 switch (pParamTypeDescr
->eTypeClass
)
144 case typelib_TypeClass_HYPER
:
145 case typelib_TypeClass_UNSIGNED_HYPER
:
146 if ((pStackedArgs
- pTopStack
) % 8)
147 pStackedArgs
+= 8 - ((pStackedArgs
- pTopStack
) % 8);
148 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = pStackedArgs
;
151 case typelib_TypeClass_ENUM
:
152 case typelib_TypeClass_LONG
:
153 case typelib_TypeClass_UNSIGNED_LONG
:
154 if ((pStackedArgs
- pTopStack
) % 4)
155 pStackedArgs
+= 4 - ((pStackedArgs
- pTopStack
) % 4);
156 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = pStackedArgs
;
159 case typelib_TypeClass_CHAR
:
160 case typelib_TypeClass_SHORT
:
161 case typelib_TypeClass_UNSIGNED_SHORT
:
162 if ((pStackedArgs
- pTopStack
) % 2)
164 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = pStackedArgs
;
167 case typelib_TypeClass_BOOLEAN
:
168 case typelib_TypeClass_BYTE
:
169 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = pStackedArgs
;
173 assert(!"should not happen");
177 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
179 else // ptr to complex value | ref
183 pCppArgs
[nPos
] = *(void **)pGPRegs
;
188 if ((pStackedArgs
- pTopStack
) % 8)
189 pStackedArgs
+= 8 - ((pStackedArgs
- pTopStack
) % 8);
190 pCppArgs
[nPos
] = pStackedArgs
;
194 if (! rParam
.bIn
) // is pure out
196 // uno out is unconstructed mem!
197 pUnoArgs
[nPos
] = alloca( pParamTypeDescr
->nSize
);
198 pTempIndices
[nTempIndices
] = nPos
;
199 // will be released at reconversion
200 ppTempParamTypeDescr
[nTempIndices
++] = pParamTypeDescr
;
203 else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr
))
205 uno_copyAndConvertData( pUnoArgs
[nPos
] =
206 alloca( pParamTypeDescr
->nSize
),
207 pCppArgs
[nPos
], pParamTypeDescr
,
208 pThis
->getBridge()->getCpp2Uno() );
209 pTempIndices
[nTempIndices
] = nPos
; // has to be reconverted
210 // will be released at reconversion
211 ppTempParamTypeDescr
[nTempIndices
++] = pParamTypeDescr
;
215 pUnoArgs
[nPos
] = pCppArgs
[nPos
];
217 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
223 uno_Any aUnoExc
; // Any will be constructed by callee
224 uno_Any
* pUnoExc
= &aUnoExc
;
226 // invoke uno dispatch call
227 (*pThis
->getUnoI()->pDispatcher
)(
228 pThis
->getUnoI(), pMemberTypeDescr
, pUnoReturn
, pUnoArgs
, &pUnoExc
);
230 // in case an exception occurred...
233 // destruct temporary in/inout params
234 for ( ; nTempIndices
--; )
236 int nIndex
= pTempIndices
[nTempIndices
];
238 if (pParams
[nIndex
].bIn
) // is in/inout => was constructed
239 uno_destructData( pUnoArgs
[nIndex
],
240 ppTempParamTypeDescr
[nTempIndices
], 0 );
241 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr
[nTempIndices
] );
243 if (pReturnTypeDescr
)
244 TYPELIB_DANGER_RELEASE( pReturnTypeDescr
);
246 CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc
,
247 pThis
->getBridge()->getUno2Cpp() ); // has to destruct the any
249 return typelib_TypeClass_VOID
;
251 else // else no exception occurred...
254 for ( ; nTempIndices
--; )
256 int nIndex
= pTempIndices
[nTempIndices
];
257 typelib_TypeDescription
* pParamTypeDescr
=
258 ppTempParamTypeDescr
[nTempIndices
];
260 if (pParams
[nIndex
].bOut
) // inout/out
262 // convert and assign
263 uno_destructData( pCppArgs
[nIndex
], pParamTypeDescr
,
265 uno_copyAndConvertData( pCppArgs
[nIndex
], pUnoArgs
[nIndex
],
266 pParamTypeDescr
, pThis
->getBridge()->getUno2Cpp() );
268 // destroy temp uno param
269 uno_destructData( pUnoArgs
[nIndex
], pParamTypeDescr
, 0 );
271 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
274 if (pCppReturn
) // has complex return
276 if (pUnoReturn
!= pCppReturn
) // needs reconversion
278 uno_copyAndConvertData( pCppReturn
, pUnoReturn
,
279 pReturnTypeDescr
, pThis
->getBridge()->getUno2Cpp() );
280 // destroy temp uno return
281 uno_destructData( pUnoReturn
, pReturnTypeDescr
, 0 );
283 *(void **)pRegisterReturn
= pCppReturn
;
285 if (pReturnTypeDescr
)
287 typelib_TypeClass eRet
=
288 (typelib_TypeClass
)pReturnTypeDescr
->eTypeClass
;
289 TYPELIB_DANGER_RELEASE( pReturnTypeDescr
);
293 return typelib_TypeClass_VOID
;
298 static void cpp_mediate(sal_Int32 nFunctionIndex
,
299 sal_Int32 nVtableOffset
,
302 sal_Int64 nRegReturn
;
303 sal_Int64
*pRegisterReturn
= &nRegReturn
;
305 // pCallStack: x8, lr, d0..d7, x0..x7, rest of params originally on stack
306 // _this_ ptr is patched cppu_XInterfaceProxy object
307 void *pThis
= pCallStack
[2 + 8];
309 pThis
= static_cast< char * >(pThis
) - nVtableOffset
;
310 bridges::cpp_uno::shared::CppInterfaceProxy
* pCppI
=
311 bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
314 typelib_InterfaceTypeDescription
* pTypeDescr
= pCppI
->getTypeDescr();
316 // determine called method
317 assert( nFunctionIndex
< pTypeDescr
->nMapFunctionIndexToMemberIndex
);
319 if (nFunctionIndex
>= pTypeDescr
->nMapFunctionIndexToMemberIndex
)
321 throw RuntimeException( "illegal vtable index!", (XInterface
*)pCppI
);
324 sal_Int32 nMemberPos
=
325 pTypeDescr
->pMapFunctionIndexToMemberIndex
[nFunctionIndex
];
326 assert( nMemberPos
< pTypeDescr
->nAllMembers
);
328 TypeDescription
aMemberDescr( pTypeDescr
->ppAllMembers
[nMemberPos
] );
330 typelib_TypeClass eRet
;
331 switch (aMemberDescr
.get()->eTypeClass
)
333 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
335 if (pTypeDescr
->pMapMemberIndexToFunctionIndex
[nMemberPos
] ==
340 pCppI
, aMemberDescr
.get(),
341 ((typelib_InterfaceAttributeTypeDescription
*)aMemberDescr
.get())->pAttributeTypeRef
,
343 pCallStack
, pRegisterReturn
);
348 typelib_MethodParameter aParam
;
350 ((typelib_InterfaceAttributeTypeDescription
*)aMemberDescr
.get())->pAttributeTypeRef
;
351 aParam
.bIn
= sal_True
;
352 aParam
.bOut
= sal_False
;
355 pCppI
, aMemberDescr
.get(),
356 0, // indicates void return
358 pCallStack
, pRegisterReturn
);
362 case typelib_TypeClass_INTERFACE_METHOD
:
365 switch (nFunctionIndex
)
368 pCppI
->acquireProxy(); // non virtual call!
369 eRet
= typelib_TypeClass_VOID
;
372 pCppI
->releaseProxy(); // non virtual call!
373 eRet
= typelib_TypeClass_VOID
;
375 case 0: // queryInterface() opt
377 typelib_TypeDescription
* pTD
= 0;
378 TYPELIB_DANGER_GET(&pTD
,
379 reinterpret_cast<Type
*>(pCallStack
[2])->getTypeLibType());
382 XInterface
* pInterface
= 0;
383 (*pCppI
->getBridge()->getCppEnv()->getRegisteredInterface
)(
384 pCppI
->getBridge()->getCppEnv(),
385 (void **)&pInterface
, pCppI
->getOid().pData
,
386 (typelib_InterfaceTypeDescription
*)pTD
);
391 reinterpret_cast< uno_Any
* >( pCallStack
[0] ),
392 &pInterface
, pTD
, cpp_acquire
);
393 pInterface
->release();
394 TYPELIB_DANGER_RELEASE( pTD
);
395 *(void **)pRegisterReturn
= pCallStack
[0];
396 eRet
= typelib_TypeClass_ANY
;
399 TYPELIB_DANGER_RELEASE( pTD
);
401 } // else perform queryInterface()
405 pCppI
, aMemberDescr
.get(),
406 ((typelib_InterfaceMethodTypeDescription
*)aMemberDescr
.get())->pReturnTypeRef
,
407 ((typelib_InterfaceMethodTypeDescription
*)aMemberDescr
.get())->nParams
,
408 ((typelib_InterfaceMethodTypeDescription
*)aMemberDescr
.get())->pParams
,
409 pCallStack
, pRegisterReturn
);
415 throw RuntimeException( "no member description found!", (XInterface
*)pCppI
);
425 * is called on incoming vtable calls
426 * (called by asm snippets)
429 extern "C" void cpp_vtable_call( sal_Int32 func
, sal_Int32 offset
,
432 cpp_mediate(func
, offset
, pStack
);
437 unsigned char *codeSnippet(const typelib_InterfaceTypeDescription
*type
,
438 const typelib_TypeDescription
*member
,
439 sal_Int32 functionIndex
,
440 sal_Int32 vtableOffset
)
442 // For now temporarily assert when we get here. The intent is
443 // that we won't need the code snippets at all on iOS.
446 assert(functionIndex
< nFunIndexes
);
447 if (!(functionIndex
< nFunIndexes
))
450 assert(vtableOffset
< nVtableOffsets
);
451 if (!(vtableOffset
< nVtableOffsets
))
454 // The codeSnippets table is indexed by functionIndex and vtableOffset
456 int index
= functionIndex
*nVtableOffsets
+ vtableOffset
;
457 unsigned char *result
= ((unsigned char *) &codeSnippets
) + codeSnippets
[index
];
459 SAL_INFO( "bridges", "codeSnippet(" << OUString(type
->aBase
.pTypeName
) << "::" << OUString(member
->pTypeName
) << "): [" << functionIndex
<< "," << vtableOffset
<< "]=" << (void *) result
<< " (" << std::hex
<< ((int*)result
)[0] << "," << ((int*)result
)[1] << "," << ((int*)result
)[2] << "," << ((int*)result
)[3] << ")");
465 struct bridges::cpp_uno::shared::VtableFactory::Slot
{ void const * fn
; };
467 bridges::cpp_uno::shared::VtableFactory::Slot
*
468 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block
)
470 return static_cast< Slot
* >(block
) + 2;
473 std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(
476 return (slotCount
+ 2) * sizeof (Slot
);
480 // Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast
481 // on such proxy objects not crash:
485 bridges::cpp_uno::shared::VtableFactory::Slot
*
486 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
487 void * block
, sal_Int32 slotCount
, sal_Int32
,
488 typelib_InterfaceTypeDescription
*)
490 Slot
* slots
= mapBlockToVtable(block
);
492 slots
[-1].fn
= &typeid(ProxyRtti
);
493 return slots
+ slotCount
;
496 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
498 unsigned char * code
,
499 typelib_InterfaceTypeDescription
const * type
,
500 sal_Int32 functionOffset
,
501 sal_Int32 functionCount
,
502 sal_Int32 vtableOffset
)
504 (*slots
) -= functionCount
;
506 for (sal_Int32 i
= 0; i
< type
->nMembers
; ++i
)
508 typelib_TypeDescription
* member
= 0;
509 TYPELIB_DANGER_GET(&member
, type
->ppMembers
[i
]);
511 switch (member
->eTypeClass
)
513 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
515 typelib_InterfaceAttributeTypeDescription
*pAttrTD
=
516 reinterpret_cast<typelib_InterfaceAttributeTypeDescription
*>( member
);
519 (s
++)->fn
= codeSnippet( type
, member
, functionOffset
++, vtableOffset
);
522 if (!pAttrTD
->bReadOnly
)
524 (s
++)->fn
= codeSnippet( type
, member
, functionOffset
++, vtableOffset
);
528 case typelib_TypeClass_INTERFACE_METHOD
:
530 (s
++)->fn
= codeSnippet( type
, member
, functionOffset
++, vtableOffset
);
537 TYPELIB_DANGER_RELEASE(member
);
544 void bridges::cpp_uno::shared::VtableFactory::flushCode(
545 unsigned char const *, unsigned char const *)
547 // No dynamic code generation so nothing to flush
551 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */