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 .
22 #include <rtl/alloc.h>
23 #include <sal/log.hxx>
25 #include <com/sun/star/uno/genfunc.hxx>
26 #include "com/sun/star/uno/RuntimeException.hpp"
28 #include <typelib/typedescription.hxx>
31 #include "cppinterfaceproxy.hxx"
33 #include "vtablefactory.hxx"
43 using namespace ::osl
;
44 using namespace ::com::sun::star::uno
;
49 static typelib_TypeClass
cpp2uno_call(
50 bridges::cpp_uno::shared::CppInterfaceProxy
* pThis
,
51 const typelib_TypeDescription
* pMemberTypeDescr
,
52 typelib_TypeDescriptionReference
* pReturnTypeRef
,
53 sal_Int32 nParams
, typelib_MethodParameter
* pParams
,
55 sal_Int64
* pRegisterReturn
/* space for register return */ )
57 // pCallStack: ret, [return ptr], this, params
58 char * pTopStack
= (char *)(pCallStack
+ 0);
59 char * pCppStack
= pTopStack
;
63 char * pFloatArgs
= (char *)(pCppStack
- 64);
66 typelib_TypeDescription
* pReturnTypeDescr
= 0;
68 TYPELIB_DANGER_GET( &pReturnTypeDescr
, pReturnTypeRef
);
70 void * pUnoReturn
= 0;
71 // complex return ptr: if != 0 && != pUnoReturn, reconversion need
72 void * pCppReturn
= 0;
76 if (!arm::return_in_hidden_param(pReturnTypeRef
))
77 pUnoReturn
= pRegisterReturn
; // direct way for simple types
78 else // complex return via ptr (pCppReturn)
80 pCppReturn
= *(void **)pCppStack
;
81 pCppStack
+= sizeof(void *);
83 pUnoReturn
= (bridges::cpp_uno::shared::relatesToInterfaceType(
85 ? alloca( pReturnTypeDescr
->nSize
)
86 : pCppReturn
); // direct way
90 pCppStack
+= sizeof( void* );
93 static_assert(sizeof(void *) == sizeof(sal_Int32
),
94 "### unexpected size!");
96 void ** pUnoArgs
= (void **)alloca( 4 * sizeof(void *) * nParams
);
97 void ** pCppArgs
= pUnoArgs
+ nParams
;
98 // indices of values this have to be converted (interface conversion
100 sal_Int32
* pTempIndices
= (sal_Int32
*)(pUnoArgs
+ (2 * nParams
));
101 // type descriptions for reconversions
102 typelib_TypeDescription
** ppTempParamTypeDescr
=
103 (typelib_TypeDescription
**)(pUnoArgs
+ (3 * nParams
));
105 sal_Int32 nTempIndices
= 0;
107 for ( sal_Int32 nPos
= 0; nPos
< nParams
; ++nPos
)
109 const typelib_MethodParameter
& rParam
= pParams
[nPos
];
110 typelib_TypeDescription
* pParamTypeDescr
= 0;
111 TYPELIB_DANGER_GET( &pParamTypeDescr
, rParam
.pTypeRef
);
114 bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr
))
117 switch (pParamTypeDescr
->eTypeClass
)
119 case typelib_TypeClass_HYPER
:
120 case typelib_TypeClass_UNSIGNED_HYPER
:
121 #ifndef __ARM_PCS_VFP
122 case typelib_TypeClass_DOUBLE
:
124 if ((pCppStack
- pTopStack
) % 8) pCppStack
+=sizeof(sal_Int32
); //align to 8
131 // For armhf we get the floating point arguments from a different area of the stack
133 if (pParamTypeDescr
->eTypeClass
== typelib_TypeClass_FLOAT
)
135 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = pFloatArgs
;
136 pFloatArgs
+= sizeof(float);
138 if (pParamTypeDescr
->eTypeClass
== typelib_TypeClass_DOUBLE
)
140 if ((pFloatArgs
- pTopStack
) % 8) pFloatArgs
+=sizeof(float); //align to 8
141 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = pFloatArgs
;
142 pFloatArgs
+= sizeof(double);
143 if (++dc
== arm::MAX_FPR_REGS
) {
144 if (pCppStack
- pTopStack
< 16)
145 pCppStack
= pTopStack
+ 16;
146 pFloatArgs
= pCppStack
;
150 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = pCppStack
;
152 switch (pParamTypeDescr
->eTypeClass
)
154 case typelib_TypeClass_HYPER
:
155 case typelib_TypeClass_UNSIGNED_HYPER
:
156 #ifndef __ARM_PCS_VFP
157 case typelib_TypeClass_DOUBLE
:
159 pCppStack
+= sizeof(sal_Int32
); // extra long
165 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
167 else // ptr to complex value | ref
169 pCppArgs
[nPos
] = *(void **)pCppStack
;
171 if (! rParam
.bIn
) // is pure out
173 // uno out is unconstructed mem!
174 pUnoArgs
[nPos
] = alloca( pParamTypeDescr
->nSize
);
175 pTempIndices
[nTempIndices
] = nPos
;
176 // will be released at reconversion
177 ppTempParamTypeDescr
[nTempIndices
++] = pParamTypeDescr
;
180 else if (bridges::cpp_uno::shared::relatesToInterfaceType(
183 uno_copyAndConvertData( pUnoArgs
[nPos
] =
184 alloca( pParamTypeDescr
->nSize
),
185 *(void **)pCppStack
, pParamTypeDescr
,
186 pThis
->getBridge()->getCpp2Uno() );
187 pTempIndices
[nTempIndices
] = nPos
; // has to be reconverted
188 // will be released at reconversion
189 ppTempParamTypeDescr
[nTempIndices
++] = pParamTypeDescr
;
193 pUnoArgs
[nPos
] = *(void **)pCppStack
;
195 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
199 // use the stack for output parameters or non floating point values
201 ((pParamTypeDescr
->eTypeClass
!= typelib_TypeClass_DOUBLE
)
202 && (pParamTypeDescr
->eTypeClass
!= typelib_TypeClass_FLOAT
))
205 pCppStack
+= sizeof(sal_Int32
); // standard parameter length
209 uno_Any aUnoExc
; // Any will be constructed by callee
210 uno_Any
* pUnoExc
= &aUnoExc
;
212 // invoke uno dispatch call
213 (*pThis
->getUnoI()->pDispatcher
)(
214 pThis
->getUnoI(), pMemberTypeDescr
, pUnoReturn
, pUnoArgs
, &pUnoExc
);
216 // in case an exception occurred...
219 // destruct temporary in/inout params
220 for ( ; nTempIndices
--; )
222 sal_Int32 nIndex
= pTempIndices
[nTempIndices
];
224 if (pParams
[nIndex
].bIn
) // is in/inout => was constructed
225 uno_destructData( pUnoArgs
[nIndex
],
226 ppTempParamTypeDescr
[nTempIndices
], 0 );
227 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr
[nTempIndices
] );
229 if (pReturnTypeDescr
)
230 TYPELIB_DANGER_RELEASE( pReturnTypeDescr
);
232 CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc
,
233 pThis
->getBridge()->getUno2Cpp() ); // has to destruct the any
235 return typelib_TypeClass_VOID
;
237 else // else no exception occurred...
240 for ( ; nTempIndices
--; )
242 sal_Int32 nIndex
= pTempIndices
[nTempIndices
];
243 typelib_TypeDescription
* pParamTypeDescr
=
244 ppTempParamTypeDescr
[nTempIndices
];
246 if (pParams
[nIndex
].bOut
) // inout/out
248 // convert and assign
249 uno_destructData( pCppArgs
[nIndex
], pParamTypeDescr
,
251 uno_copyAndConvertData( pCppArgs
[nIndex
], pUnoArgs
[nIndex
],
252 pParamTypeDescr
, pThis
->getBridge()->getUno2Cpp() );
254 // destroy temp uno param
255 uno_destructData( pUnoArgs
[nIndex
], pParamTypeDescr
, 0 );
257 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
260 if (pCppReturn
) // has complex return
262 if (pUnoReturn
!= pCppReturn
) // needs reconversion
264 uno_copyAndConvertData( pCppReturn
, pUnoReturn
,
265 pReturnTypeDescr
, pThis
->getBridge()->getUno2Cpp() );
266 // destroy temp uno return
267 uno_destructData( pUnoReturn
, pReturnTypeDescr
, 0 );
269 // complex return ptr is set to eax
270 *(void **)pRegisterReturn
= pCppReturn
;
272 if (pReturnTypeDescr
)
274 typelib_TypeClass eRet
=
275 (typelib_TypeClass
)pReturnTypeDescr
->eTypeClass
;
276 TYPELIB_DANGER_RELEASE( pReturnTypeDescr
);
280 return typelib_TypeClass_VOID
;
285 static typelib_TypeClass
cpp_mediate(
286 sal_Int32 nFunctionIndex
, sal_Int32 nVtableOffset
,
288 sal_Int64
* pRegisterReturn
/* space for register return */ )
290 static_assert(sizeof(sal_Int32
)==sizeof(void *), "### unexpected!");
292 // pCallStack: [ret *], this, params
293 // _this_ ptr is patched cppu_XInterfaceProxy object
295 if( nFunctionIndex
& 0x80000000 )
297 nFunctionIndex
&= 0x7fffffff;
298 pThis
= pCallStack
[1];
302 pThis
= pCallStack
[0];
305 pThis
= static_cast< char * >(pThis
) - nVtableOffset
;
306 bridges::cpp_uno::shared::CppInterfaceProxy
* pCppI
=
307 bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
310 typelib_InterfaceTypeDescription
* pTypeDescr
= pCppI
->getTypeDescr();
312 if (nFunctionIndex
>= pTypeDescr
->nMapFunctionIndexToMemberIndex
)
316 "illegal " << OUString::unacquired(&pTypeDescr
->aBase
.pTypeName
)
317 << " vtable index " << nFunctionIndex
<< "/"
318 << pTypeDescr
->nMapFunctionIndexToMemberIndex
);
319 throw RuntimeException(
320 ("illegal " + OUString::unacquired(&pTypeDescr
->aBase
.pTypeName
)
321 + " vtable index " + OUString::number(nFunctionIndex
) + "/"
322 + OUString::number(pTypeDescr
->nMapFunctionIndexToMemberIndex
)),
323 (XInterface
*)pCppI
);
326 // determine called method
327 assert(nFunctionIndex
< pTypeDescr
->nMapFunctionIndexToMemberIndex
);
328 sal_Int32 nMemberPos
=
329 pTypeDescr
->pMapFunctionIndexToMemberIndex
[nFunctionIndex
];
330 assert(nMemberPos
< pTypeDescr
->nAllMembers
);
332 TypeDescription
aMemberDescr( pTypeDescr
->ppAllMembers
[nMemberPos
] );
334 typelib_TypeClass eRet
;
335 switch (aMemberDescr
.get()->eTypeClass
)
337 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
339 if (pTypeDescr
->pMapMemberIndexToFunctionIndex
[nMemberPos
] ==
344 pCppI
, aMemberDescr
.get(),
345 ((typelib_InterfaceAttributeTypeDescription
*)aMemberDescr
.get())->pAttributeTypeRef
,
347 pCallStack
, pRegisterReturn
);
352 typelib_MethodParameter aParam
;
354 ((typelib_InterfaceAttributeTypeDescription
*)aMemberDescr
.get())->pAttributeTypeRef
;
355 aParam
.bIn
= sal_True
;
356 aParam
.bOut
= sal_False
;
359 pCppI
, aMemberDescr
.get(),
360 0, // indicates void return
362 pCallStack
, pRegisterReturn
);
366 case typelib_TypeClass_INTERFACE_METHOD
:
369 switch (nFunctionIndex
)
372 pCppI
->acquireProxy(); // non virtual call!
373 eRet
= typelib_TypeClass_VOID
;
376 pCppI
->releaseProxy(); // non virtual call!
377 eRet
= typelib_TypeClass_VOID
;
379 case 0: // queryInterface() opt
381 typelib_TypeDescription
* pTD
= 0;
382 TYPELIB_DANGER_GET(&pTD
,
383 reinterpret_cast<Type
*>(pCallStack
[2])->getTypeLibType());
386 XInterface
* pInterface
= 0;
387 (*pCppI
->getBridge()->getCppEnv()->getRegisteredInterface
)(
388 pCppI
->getBridge()->getCppEnv(),
389 (void **)&pInterface
, pCppI
->getOid().pData
,
390 (typelib_InterfaceTypeDescription
*)pTD
);
395 reinterpret_cast< uno_Any
* >( pCallStack
[0] ),
396 &pInterface
, pTD
, cpp_acquire
);
397 pInterface
->release();
398 TYPELIB_DANGER_RELEASE( pTD
);
399 *(void **)pRegisterReturn
= pCallStack
[0];
400 eRet
= typelib_TypeClass_ANY
;
403 TYPELIB_DANGER_RELEASE( pTD
);
405 } [[fallthrough
]]; // else perform queryInterface()
408 pCppI
, aMemberDescr
.get(),
409 ((typelib_InterfaceMethodTypeDescription
*)aMemberDescr
.get())->pReturnTypeRef
,
410 ((typelib_InterfaceMethodTypeDescription
*)aMemberDescr
.get())->nParams
,
411 ((typelib_InterfaceMethodTypeDescription
*)aMemberDescr
.get())->pParams
,
412 pCallStack
, pRegisterReturn
);
418 throw RuntimeException( "no member description found!", (XInterface
*)pCppI
);
427 * is called on incoming vtable calls
428 * (called by asm snippets)
431 extern "C" sal_Int64
cpp_vtable_call( long *pFunctionAndOffset
,
434 sal_Int64 nRegReturn
;
435 typelib_TypeClass aType
= cpp_mediate( pFunctionAndOffset
[0], pFunctionAndOffset
[1], pCallStack
,
440 case typelib_TypeClass_BOOLEAN
:
441 case typelib_TypeClass_BYTE
:
442 nRegReturn
= (unsigned long)(*(unsigned char *)&nRegReturn
);
444 case typelib_TypeClass_CHAR
:
445 case typelib_TypeClass_UNSIGNED_SHORT
:
446 case typelib_TypeClass_SHORT
:
447 nRegReturn
= (unsigned long)(*(unsigned short *)&nRegReturn
);
449 case typelib_TypeClass_ENUM
:
450 case typelib_TypeClass_UNSIGNED_LONG
:
451 case typelib_TypeClass_LONG
:
452 nRegReturn
= (unsigned long)(*(unsigned int *)&nRegReturn
);
454 case typelib_TypeClass_VOID
:
464 const int codeSnippetSize
= 20;
466 unsigned char *codeSnippet(unsigned char* code
, sal_Int32 functionIndex
,
467 sal_Int32 vtableOffset
, bool bHasHiddenParam
)
470 functionIndex
|= 0x80000000;
472 unsigned long * p
= (unsigned long *)code
;
474 // ARM (not thumb) mode instructions
479 *p
++ = (unsigned long)functionIndex
;
480 *p
++ = (unsigned long)vtableOffset
;
481 *p
++ = (unsigned long)privateSnippetExecutor
;
483 return code
+ codeSnippetSize
;
487 struct bridges::cpp_uno::shared::VtableFactory::Slot
{ void * fn
; };
489 bridges::cpp_uno::shared::VtableFactory::Slot
*
490 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block
)
492 return static_cast< Slot
* >(block
) + 2;
495 std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(
498 return (slotCount
+ 2) * sizeof (Slot
) + slotCount
* codeSnippetSize
;
501 bridges::cpp_uno::shared::VtableFactory::Slot
*
502 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
503 void * block
, sal_Int32 slotCount
, sal_Int32
,
504 typelib_InterfaceTypeDescription
*)
506 Slot
* slots
= mapBlockToVtable(block
);
509 return slots
+ slotCount
;
512 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
513 Slot
** slots
, unsigned char * code
,
514 #ifdef USE_DOUBLE_MMAP
515 sal_PtrDiff writetoexecdiff
,
517 typelib_InterfaceTypeDescription
const * type
, sal_Int32 functionOffset
,
518 sal_Int32 functionCount
, sal_Int32 vtableOffset
)
520 #ifndef USE_DOUBLE_MMAP
521 const sal_PtrDiff writetoexecdiff
= 0;
523 (*slots
) -= functionCount
;
525 for (sal_Int32 i
= 0; i
< type
->nMembers
; ++i
)
527 typelib_TypeDescription
* member
= 0;
528 TYPELIB_DANGER_GET(&member
, type
->ppMembers
[i
]);
530 switch (member
->eTypeClass
)
532 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
534 typelib_InterfaceAttributeTypeDescription
*pAttrTD
=
535 reinterpret_cast<typelib_InterfaceAttributeTypeDescription
*>( member
);
538 (s
++)->fn
= code
+ writetoexecdiff
;
540 code
, functionOffset
++, vtableOffset
,
541 arm::return_in_hidden_param( pAttrTD
->pAttributeTypeRef
));
544 if (!pAttrTD
->bReadOnly
)
546 (s
++)->fn
= code
+ writetoexecdiff
;
548 code
, functionOffset
++, vtableOffset
, false);
552 case typelib_TypeClass_INTERFACE_METHOD
:
554 (s
++)->fn
= code
+ writetoexecdiff
;
556 typelib_InterfaceMethodTypeDescription
*pMethodTD
=
558 typelib_InterfaceMethodTypeDescription
* >(member
);
560 code
= codeSnippet(code
, functionOffset
++, vtableOffset
,
561 arm::return_in_hidden_param(pMethodTD
->pReturnTypeRef
));
568 TYPELIB_DANGER_RELEASE(member
);
573 void bridges::cpp_uno::shared::VtableFactory::flushCode(
574 unsigned char const *beg
, unsigned char const *end
)
577 static void (*clear_cache
)(unsigned char const*, unsigned char const*)
578 = (void (*)(unsigned char const*, unsigned char const*))
579 dlsym(RTLD_DEFAULT
, "__clear_cache");
580 (*clear_cache
)(beg
, end
);
582 cacheflush((long) beg
, (long) end
, 0);
586 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */