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 .
23 #include <rtl/alloc.h>
24 #include <sal/log.hxx>
26 #include <com/sun/star/uno/genfunc.hxx>
27 #include <com/sun/star/uno/RuntimeException.hpp>
29 #include <typelib/typedescription.hxx>
32 #include <cppinterfaceproxy.hxx>
34 #include <vtablefactory.hxx>
45 using namespace ::osl
;
46 using namespace ::com::sun::star::uno
;
51 typelib_TypeClass
cpp2uno_call(
52 bridges::cpp_uno::shared::CppInterfaceProxy
* pThis
,
53 const typelib_TypeDescription
* pMemberTypeDescr
,
54 typelib_TypeDescriptionReference
* pReturnTypeRef
,
55 sal_Int32 nParams
, typelib_MethodParameter
* pParams
,
57 sal_Int64
* pRegisterReturn
/* space for register return */ )
59 // pCallStack: ret, [return ptr], this, params
60 char * pTopStack
= reinterpret_cast<char *>(pCallStack
+ 0);
61 char * pCppStack
= pTopStack
;
65 char * pFloatArgs
= reinterpret_cast<char *>(pCppStack
- 64);
68 typelib_TypeDescription
* pReturnTypeDescr
= nullptr;
70 TYPELIB_DANGER_GET( &pReturnTypeDescr
, pReturnTypeRef
);
72 void * pUnoReturn
= nullptr;
73 // complex return ptr: if != 0 && != pUnoReturn, reconversion need
74 void * pCppReturn
= nullptr;
78 if (!arm::return_in_hidden_param(pReturnTypeRef
))
79 pUnoReturn
= pRegisterReturn
; // direct way for simple types
80 else // complex return via ptr (pCppReturn)
82 pCppReturn
= *reinterpret_cast<void **>(pCppStack
);
83 pCppStack
+= sizeof(void *);
85 pUnoReturn
= (bridges::cpp_uno::shared::relatesToInterfaceType(
87 ? alloca( pReturnTypeDescr
->nSize
)
88 : pCppReturn
); // direct way
92 pCppStack
+= sizeof( void* );
95 static_assert(sizeof(void *) == sizeof(sal_Int32
),
96 "### unexpected size!");
98 void ** pUnoArgs
= static_cast<void **>(alloca( 4 * sizeof(void *) * nParams
));
99 void ** pCppArgs
= pUnoArgs
+ nParams
;
100 // indices of values this have to be converted (interface conversion
102 sal_Int32
* pTempIndices
= reinterpret_cast<sal_Int32
*>(pUnoArgs
+ (2 * nParams
));
103 // type descriptions for reconversions
104 typelib_TypeDescription
** ppTempParamTypeDescr
=
105 reinterpret_cast<typelib_TypeDescription
**>(pUnoArgs
+ (3 * nParams
));
107 sal_Int32 nTempIndices
= 0;
109 for ( sal_Int32 nPos
= 0; nPos
< nParams
; ++nPos
)
111 const typelib_MethodParameter
& rParam
= pParams
[nPos
];
112 typelib_TypeDescription
* pParamTypeDescr
= nullptr;
113 TYPELIB_DANGER_GET( &pParamTypeDescr
, rParam
.pTypeRef
);
116 bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr
))
119 switch (pParamTypeDescr
->eTypeClass
)
121 case typelib_TypeClass_HYPER
:
122 case typelib_TypeClass_UNSIGNED_HYPER
:
123 #ifndef __ARM_PCS_VFP
124 case typelib_TypeClass_DOUBLE
:
126 if ((pCppStack
- pTopStack
) % 8) pCppStack
+=sizeof(sal_Int32
); //align to 8
133 // For armhf we get the floating point arguments from a different area of the stack
135 if (pParamTypeDescr
->eTypeClass
== typelib_TypeClass_FLOAT
)
137 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = pFloatArgs
;
138 pFloatArgs
+= sizeof(float);
140 if (pParamTypeDescr
->eTypeClass
== typelib_TypeClass_DOUBLE
)
142 if ((pFloatArgs
- pTopStack
) % 8) pFloatArgs
+=sizeof(float); //align to 8
143 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = pFloatArgs
;
144 pFloatArgs
+= sizeof(double);
145 if (++dc
== arm::MAX_FPR_REGS
) {
146 if (pCppStack
- pTopStack
< 16)
147 pCppStack
= pTopStack
+ 16;
148 pFloatArgs
= pCppStack
;
152 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = pCppStack
;
154 switch (pParamTypeDescr
->eTypeClass
)
156 case typelib_TypeClass_HYPER
:
157 case typelib_TypeClass_UNSIGNED_HYPER
:
158 #ifndef __ARM_PCS_VFP
159 case typelib_TypeClass_DOUBLE
:
161 pCppStack
+= sizeof(sal_Int32
); // extra long
167 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
169 else // ptr to complex value | ref
171 pCppArgs
[nPos
] = *reinterpret_cast<void **>(pCppStack
);
173 if (! rParam
.bIn
) // is pure out
175 // uno out is unconstructed mem!
176 pUnoArgs
[nPos
] = alloca( pParamTypeDescr
->nSize
);
177 pTempIndices
[nTempIndices
] = nPos
;
178 // will be released at reconversion
179 ppTempParamTypeDescr
[nTempIndices
++] = pParamTypeDescr
;
182 else if (bridges::cpp_uno::shared::relatesToInterfaceType(
185 uno_copyAndConvertData( pUnoArgs
[nPos
] =
186 alloca( pParamTypeDescr
->nSize
),
187 *reinterpret_cast<void **>(pCppStack
), pParamTypeDescr
,
188 pThis
->getBridge()->getCpp2Uno() );
189 pTempIndices
[nTempIndices
] = nPos
; // has to be reconverted
190 // will be released at reconversion
191 ppTempParamTypeDescr
[nTempIndices
++] = pParamTypeDescr
;
195 pUnoArgs
[nPos
] = *reinterpret_cast<void **>(pCppStack
);
197 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
201 // use the stack for output parameters or non floating point values
203 ((pParamTypeDescr
->eTypeClass
!= typelib_TypeClass_DOUBLE
)
204 && (pParamTypeDescr
->eTypeClass
!= typelib_TypeClass_FLOAT
))
207 pCppStack
+= sizeof(sal_Int32
); // standard parameter length
211 uno_Any aUnoExc
; // Any will be constructed by callee
212 uno_Any
* pUnoExc
= &aUnoExc
;
214 // invoke uno dispatch call
215 (*pThis
->getUnoI()->pDispatcher
)(
216 pThis
->getUnoI(), pMemberTypeDescr
, pUnoReturn
, pUnoArgs
, &pUnoExc
);
218 // in case an exception occurred...
221 // destruct temporary in/inout params
222 for ( ; nTempIndices
--; )
224 sal_Int32 nIndex
= pTempIndices
[nTempIndices
];
226 if (pParams
[nIndex
].bIn
) // is in/inout => was constructed
227 uno_destructData( pUnoArgs
[nIndex
],
228 ppTempParamTypeDescr
[nTempIndices
], nullptr );
229 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr
[nTempIndices
] );
231 if (pReturnTypeDescr
)
232 TYPELIB_DANGER_RELEASE( pReturnTypeDescr
);
234 CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc
,
235 pThis
->getBridge()->getUno2Cpp() ); // has to destruct the any
237 return typelib_TypeClass_VOID
;
239 else // else no exception occurred...
242 for ( ; nTempIndices
--; )
244 sal_Int32 nIndex
= pTempIndices
[nTempIndices
];
245 typelib_TypeDescription
* pParamTypeDescr
=
246 ppTempParamTypeDescr
[nTempIndices
];
248 if (pParams
[nIndex
].bOut
) // inout/out
250 // convert and assign
251 uno_destructData( pCppArgs
[nIndex
], pParamTypeDescr
,
253 uno_copyAndConvertData( pCppArgs
[nIndex
], pUnoArgs
[nIndex
],
254 pParamTypeDescr
, pThis
->getBridge()->getUno2Cpp() );
256 // destroy temp uno param
257 uno_destructData( pUnoArgs
[nIndex
], pParamTypeDescr
, nullptr );
259 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
262 if (pCppReturn
) // has complex return
264 if (pUnoReturn
!= pCppReturn
) // needs reconversion
266 uno_copyAndConvertData( pCppReturn
, pUnoReturn
,
267 pReturnTypeDescr
, pThis
->getBridge()->getUno2Cpp() );
268 // destroy temp uno return
269 uno_destructData( pUnoReturn
, pReturnTypeDescr
, nullptr );
271 // complex return ptr is set to eax
272 *reinterpret_cast<void **>(pRegisterReturn
) = pCppReturn
;
274 if (pReturnTypeDescr
)
276 typelib_TypeClass eRet
= pReturnTypeDescr
->eTypeClass
;
277 TYPELIB_DANGER_RELEASE( pReturnTypeDescr
);
281 return typelib_TypeClass_VOID
;
286 typelib_TypeClass
cpp_mediate(
287 sal_Int32 nFunctionIndex
, sal_Int32 nVtableOffset
,
289 sal_Int64
* pRegisterReturn
/* space for register return */ )
291 static_assert(sizeof(sal_Int32
)==sizeof(void *), "### unexpected!");
293 // pCallStack: [ret *], this, params
294 // _this_ ptr is patched cppu_XInterfaceProxy object
296 if( nFunctionIndex
& 0x80000000 )
298 nFunctionIndex
&= 0x7fffffff;
299 pThis
= pCallStack
[1];
303 pThis
= pCallStack
[0];
306 pThis
= static_cast< char * >(pThis
) - nVtableOffset
;
307 bridges::cpp_uno::shared::CppInterfaceProxy
* pCppI
=
308 bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
311 typelib_InterfaceTypeDescription
* pTypeDescr
= pCppI
->getTypeDescr();
313 if (nFunctionIndex
>= pTypeDescr
->nMapFunctionIndexToMemberIndex
)
317 "illegal " << OUString::unacquired(&pTypeDescr
->aBase
.pTypeName
)
318 << " vtable index " << nFunctionIndex
<< "/"
319 << pTypeDescr
->nMapFunctionIndexToMemberIndex
);
320 throw RuntimeException(
321 ("illegal " + OUString::unacquired(&pTypeDescr
->aBase
.pTypeName
)
322 + " vtable index " + OUString::number(nFunctionIndex
) + "/"
323 + OUString::number(pTypeDescr
->nMapFunctionIndexToMemberIndex
)),
324 reinterpret_cast<XInterface
*>(pCppI
));
327 // determine called method
328 assert(nFunctionIndex
< pTypeDescr
->nMapFunctionIndexToMemberIndex
);
329 sal_Int32 nMemberPos
=
330 pTypeDescr
->pMapFunctionIndexToMemberIndex
[nFunctionIndex
];
331 assert(nMemberPos
< pTypeDescr
->nAllMembers
);
333 TypeDescription
aMemberDescr( pTypeDescr
->ppAllMembers
[nMemberPos
] );
335 typelib_TypeClass eRet
;
336 switch (aMemberDescr
.get()->eTypeClass
)
338 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
340 if (pTypeDescr
->pMapMemberIndexToFunctionIndex
[nMemberPos
] ==
345 pCppI
, aMemberDescr
.get(),
346 reinterpret_cast<typelib_InterfaceAttributeTypeDescription
*>(aMemberDescr
.get())->pAttributeTypeRef
,
347 0, nullptr, // no params
348 pCallStack
, pRegisterReturn
);
353 typelib_MethodParameter aParam
;
355 reinterpret_cast<typelib_InterfaceAttributeTypeDescription
*>(aMemberDescr
.get())->pAttributeTypeRef
;
360 pCppI
, aMemberDescr
.get(),
361 nullptr, // indicates void return
363 pCallStack
, pRegisterReturn
);
367 case typelib_TypeClass_INTERFACE_METHOD
:
370 switch (nFunctionIndex
)
373 pCppI
->acquireProxy(); // non virtual call!
374 eRet
= typelib_TypeClass_VOID
;
377 pCppI
->releaseProxy(); // non virtual call!
378 eRet
= typelib_TypeClass_VOID
;
380 case 0: // queryInterface() opt
382 typelib_TypeDescription
* pTD
= nullptr;
383 TYPELIB_DANGER_GET(&pTD
,
384 static_cast<Type
*>(pCallStack
[2])->getTypeLibType());
387 XInterface
* pInterface
= nullptr;
388 (*pCppI
->getBridge()->getCppEnv()->getRegisteredInterface
)(
389 pCppI
->getBridge()->getCppEnv(),
390 reinterpret_cast<void **>(&pInterface
), pCppI
->getOid().pData
,
391 reinterpret_cast<typelib_InterfaceTypeDescription
*>(pTD
) );
396 static_cast< uno_Any
* >( pCallStack
[0] ),
397 &pInterface
, pTD
, cpp_acquire
);
398 pInterface
->release();
399 TYPELIB_DANGER_RELEASE( pTD
);
400 *reinterpret_cast<void **>(pRegisterReturn
) = pCallStack
[0];
401 eRet
= typelib_TypeClass_ANY
;
404 TYPELIB_DANGER_RELEASE( pTD
);
406 } [[fallthrough
]]; // else perform queryInterface()
409 pCppI
, aMemberDescr
.get(),
410 reinterpret_cast<typelib_InterfaceMethodTypeDescription
*>(aMemberDescr
.get())->pReturnTypeRef
,
411 reinterpret_cast<typelib_InterfaceMethodTypeDescription
*>(aMemberDescr
.get())->nParams
,
412 reinterpret_cast<typelib_InterfaceMethodTypeDescription
*>(aMemberDescr
.get())->pParams
,
413 pCallStack
, pRegisterReturn
);
419 throw RuntimeException( "no member description found!", reinterpret_cast<XInterface
*>(pCppI
) );
428 * is called on incoming vtable calls
429 * (called by asm snippets)
432 sal_Int64
cpp_vtable_call( long *pFunctionAndOffset
,
435 sal_Int64 nRegReturn
;
436 typelib_TypeClass aType
= cpp_mediate( pFunctionAndOffset
[0], pFunctionAndOffset
[1], pCallStack
,
441 case typelib_TypeClass_BOOLEAN
:
442 case typelib_TypeClass_BYTE
:
443 nRegReturn
= static_cast<unsigned long>(*reinterpret_cast<unsigned char *>(&nRegReturn
));
445 case typelib_TypeClass_CHAR
:
446 case typelib_TypeClass_UNSIGNED_SHORT
:
447 case typelib_TypeClass_SHORT
:
448 nRegReturn
= static_cast<unsigned long>(*reinterpret_cast<unsigned short *>(&nRegReturn
));
450 case typelib_TypeClass_ENUM
:
451 case typelib_TypeClass_UNSIGNED_LONG
:
452 case typelib_TypeClass_LONG
:
453 nRegReturn
= static_cast<unsigned long>(*reinterpret_cast<unsigned int *>(&nRegReturn
));
455 case typelib_TypeClass_VOID
:
465 const int codeSnippetSize
= 20;
467 unsigned char *codeSnippet(unsigned char* code
, sal_Int32 functionIndex
,
468 sal_Int32 vtableOffset
, bool bHasHiddenParam
)
471 functionIndex
|= 0x80000000;
473 unsigned long * p
= reinterpret_cast<unsigned long *>(code
);
475 // ARM (not thumb) mode instructions
480 *p
++ = static_cast<unsigned long>(functionIndex
);
481 *p
++ = static_cast<unsigned long>(vtableOffset
);
482 *p
++ = reinterpret_cast<unsigned long>(privateSnippetExecutor
);
484 return code
+ codeSnippetSize
;
488 struct bridges::cpp_uno::shared::VtableFactory::Slot
{ void const * fn
; };
490 bridges::cpp_uno::shared::VtableFactory::Slot
*
491 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block
)
493 return static_cast< Slot
* >(block
) + 2;
496 std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(
499 return (slotCount
+ 2) * sizeof (Slot
) + slotCount
* codeSnippetSize
;
503 // Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast
504 // on such proxy objects not crash:
508 bridges::cpp_uno::shared::VtableFactory::Slot
*
509 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
510 void * block
, sal_Int32 slotCount
, sal_Int32
,
511 typelib_InterfaceTypeDescription
*)
513 Slot
* slots
= mapBlockToVtable(block
);
514 slots
[-2].fn
= nullptr;
515 slots
[-1].fn
= &typeid(ProxyRtti
);
516 return slots
+ slotCount
;
519 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
520 Slot
** slots
, unsigned char * code
,
521 #ifdef USE_DOUBLE_MMAP
522 sal_PtrDiff writetoexecdiff
,
524 typelib_InterfaceTypeDescription
const * type
, sal_Int32 functionOffset
,
525 sal_Int32 functionCount
, sal_Int32 vtableOffset
)
527 #ifndef USE_DOUBLE_MMAP
528 const sal_PtrDiff writetoexecdiff
= 0;
530 (*slots
) -= functionCount
;
532 for (sal_Int32 i
= 0; i
< type
->nMembers
; ++i
)
534 typelib_TypeDescription
* member
= nullptr;
535 TYPELIB_DANGER_GET(&member
, type
->ppMembers
[i
]);
537 switch (member
->eTypeClass
)
539 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
541 typelib_InterfaceAttributeTypeDescription
*pAttrTD
=
542 reinterpret_cast<typelib_InterfaceAttributeTypeDescription
*>( member
);
545 (s
++)->fn
= code
+ writetoexecdiff
;
547 code
, functionOffset
++, vtableOffset
,
548 arm::return_in_hidden_param( pAttrTD
->pAttributeTypeRef
));
551 if (!pAttrTD
->bReadOnly
)
553 (s
++)->fn
= code
+ writetoexecdiff
;
555 code
, functionOffset
++, vtableOffset
, false);
559 case typelib_TypeClass_INTERFACE_METHOD
:
561 (s
++)->fn
= code
+ writetoexecdiff
;
563 typelib_InterfaceMethodTypeDescription
*pMethodTD
=
565 typelib_InterfaceMethodTypeDescription
* >(member
);
567 code
= codeSnippet(code
, functionOffset
++, vtableOffset
,
568 arm::return_in_hidden_param(pMethodTD
->pReturnTypeRef
));
575 TYPELIB_DANGER_RELEASE(member
);
580 void bridges::cpp_uno::shared::VtableFactory::flushCode(
581 unsigned char const *beg
, unsigned char const *end
)
584 static void (*clear_cache
)(unsigned char const*, unsigned char const*)
585 = reinterpret_cast<void (*)(unsigned char const*, unsigned char const*)>
586 (dlsym(RTLD_DEFAULT
, "__clear_cache"));
587 (*clear_cache
)(beg
, end
);
589 cacheflush((long) beg
, (long) end
, 0);
593 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */