nss: upgrade to release 3.73
[LibreOffice.git] / bridges / source / cpp_uno / gcc3_linux_arm / cpp2uno.cxx
blob4ef17b8542e1b8ace0b538969b52bd961d49562c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <malloc.h>
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"
27 #include <uno/data.h>
28 #include <typelib/typedescription.hxx>
30 #include "bridge.hxx"
31 #include "cppinterfaceproxy.hxx"
32 #include "types.hxx"
33 #include "vtablefactory.hxx"
35 #include "share.hxx"
37 #include <dlfcn.h>
39 #ifdef ANDROID
40 #include <unistd.h>
41 #endif
43 using namespace ::osl;
44 using namespace ::com::sun::star::uno;
46 namespace
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,
54 void ** pCallStack,
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;
61 #ifdef __ARM_PCS_VFP
62 int dc = 0;
63 char * pFloatArgs = (char *)(pCppStack - 64);
64 #endif
65 // return
66 typelib_TypeDescription * pReturnTypeDescr = 0;
67 if (pReturnTypeRef)
68 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
70 void * pUnoReturn = 0;
71 // complex return ptr: if != 0 && != pUnoReturn, reconversion need
72 void * pCppReturn = 0;
74 if (pReturnTypeDescr)
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(
84 pReturnTypeDescr )
85 ? alloca( pReturnTypeDescr->nSize )
86 : pCppReturn); // direct way
89 // pop this
90 pCppStack += sizeof( void* );
92 // stack space
93 static_assert(sizeof(void *) == sizeof(sal_Int32),
94 "### unexpected size!");
95 // parameters
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
99 // cpp<=>uno)
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 );
113 if (!rParam.bOut &&
114 bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
116 #ifdef __ARM_EABI__
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:
123 #endif
124 if ((pCppStack - pTopStack) % 8) pCppStack+=sizeof(sal_Int32); //align to 8
125 break;
126 default:
127 break;
129 #endif
131 // For armhf we get the floating point arguments from a different area of the stack
132 #ifdef __ARM_PCS_VFP
133 if (pParamTypeDescr->eTypeClass == typelib_TypeClass_FLOAT)
135 pCppArgs[nPos] = pUnoArgs[nPos] = pFloatArgs;
136 pFloatArgs += sizeof(float);
137 } else
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;
148 } else
149 #endif
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:
158 #endif
159 pCppStack += sizeof(sal_Int32); // extra long
160 break;
161 default:
162 break;
164 // no longer needed
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;
179 // is in/inout
180 else if (bridges::cpp_uno::shared::relatesToInterfaceType(
181 pParamTypeDescr ))
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;
191 else // direct way
193 pUnoArgs[nPos] = *(void **)pCppStack;
194 // no longer needed
195 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
198 #ifdef __ARM_PCS_VFP
199 // use the stack for output parameters or non floating point values
200 if (rParam.bOut ||
201 ((pParamTypeDescr->eTypeClass != typelib_TypeClass_DOUBLE)
202 && (pParamTypeDescr->eTypeClass != typelib_TypeClass_FLOAT))
204 #endif
205 pCppStack += sizeof(sal_Int32); // standard parameter length
208 // ExceptionHolder
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...
217 if (pUnoExc)
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
234 // is here for dummy
235 return typelib_TypeClass_VOID;
237 else // else no exception occurred...
239 // temporary params
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,
250 cpp_release );
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 );
259 // return
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 );
277 return eRet;
279 else
280 return typelib_TypeClass_VOID;
285 static typelib_TypeClass cpp_mediate(
286 sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
287 void ** pCallStack,
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
294 void *pThis;
295 if( nFunctionIndex & 0x80000000 )
297 nFunctionIndex &= 0x7fffffff;
298 pThis = pCallStack[1];
300 else
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(
308 pThis);
310 typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
312 if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
314 SAL_WARN(
315 "bridges",
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] ==
340 nFunctionIndex)
342 // is GET method
343 eRet = cpp2uno_call(
344 pCppI, aMemberDescr.get(),
345 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef,
346 0, 0, // no params
347 pCallStack, pRegisterReturn );
349 else
351 // is SET method
352 typelib_MethodParameter aParam;
353 aParam.pTypeRef =
354 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef;
355 aParam.bIn = sal_True;
356 aParam.bOut = sal_False;
358 eRet = cpp2uno_call(
359 pCppI, aMemberDescr.get(),
360 0, // indicates void return
361 1, &aParam,
362 pCallStack, pRegisterReturn );
364 break;
366 case typelib_TypeClass_INTERFACE_METHOD:
368 // is METHOD
369 switch (nFunctionIndex)
371 case 1: // acquire()
372 pCppI->acquireProxy(); // non virtual call!
373 eRet = typelib_TypeClass_VOID;
374 break;
375 case 2: // release()
376 pCppI->releaseProxy(); // non virtual call!
377 eRet = typelib_TypeClass_VOID;
378 break;
379 case 0: // queryInterface() opt
381 typelib_TypeDescription * pTD = 0;
382 TYPELIB_DANGER_GET(&pTD,
383 reinterpret_cast<Type *>(pCallStack[2])->getTypeLibType());
384 if (pTD)
386 XInterface * pInterface = 0;
387 (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
388 pCppI->getBridge()->getCppEnv(),
389 (void **)&pInterface, pCppI->getOid().pData,
390 (typelib_InterfaceTypeDescription *)pTD );
392 if (pInterface)
394 ::uno_any_construct(
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;
401 break;
403 TYPELIB_DANGER_RELEASE( pTD );
405 } [[fallthrough]]; // else perform queryInterface()
406 default:
407 eRet = cpp2uno_call(
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 );
414 break;
416 default:
418 throw RuntimeException( "no member description found!", (XInterface *)pCppI );
422 return eRet;
427 * is called on incoming vtable calls
428 * (called by asm snippets)
431 extern "C" sal_Int64 cpp_vtable_call( long *pFunctionAndOffset,
432 void **pCallStack )
434 sal_Int64 nRegReturn;
435 typelib_TypeClass aType = cpp_mediate( pFunctionAndOffset[0], pFunctionAndOffset[1], pCallStack,
436 &nRegReturn );
438 switch( aType )
440 case typelib_TypeClass_BOOLEAN:
441 case typelib_TypeClass_BYTE:
442 nRegReturn = (unsigned long)(*(unsigned char *)&nRegReturn);
443 break;
444 case typelib_TypeClass_CHAR:
445 case typelib_TypeClass_UNSIGNED_SHORT:
446 case typelib_TypeClass_SHORT:
447 nRegReturn = (unsigned long)(*(unsigned short *)&nRegReturn);
448 break;
449 case typelib_TypeClass_ENUM:
450 case typelib_TypeClass_UNSIGNED_LONG:
451 case typelib_TypeClass_LONG:
452 nRegReturn = (unsigned long)(*(unsigned int *)&nRegReturn);
453 break;
454 case typelib_TypeClass_VOID:
455 default:
456 break;
459 return nRegReturn;
462 namespace
464 const int codeSnippetSize = 20;
466 unsigned char *codeSnippet(unsigned char* code, sal_Int32 functionIndex,
467 sal_Int32 vtableOffset, bool bHasHiddenParam)
469 if (bHasHiddenParam)
470 functionIndex |= 0x80000000;
472 unsigned long * p = (unsigned long *)code;
474 // ARM (not thumb) mode instructions
475 // mov ip, pc
476 *p++ = 0xE1A0C00F;
477 // ldr pc, [pc, #4]
478 *p++ = 0xE59FF004;
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(
496 sal_Int32 slotCount)
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);
507 slots[-2].fn = 0;
508 slots[-1].fn = 0;
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,
516 #endif
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;
522 #endif
523 (*slots) -= functionCount;
524 Slot * s = *slots;
525 for (sal_Int32 i = 0; i < type->nMembers; ++i)
527 typelib_TypeDescription * member = 0;
528 TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
529 assert(member != 0);
530 switch (member->eTypeClass)
532 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
534 typelib_InterfaceAttributeTypeDescription *pAttrTD =
535 reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( member );
537 // Getter:
538 (s++)->fn = code + writetoexecdiff;
539 code = codeSnippet(
540 code, functionOffset++, vtableOffset,
541 arm::return_in_hidden_param( pAttrTD->pAttributeTypeRef ));
543 // Setter:
544 if (!pAttrTD->bReadOnly)
546 (s++)->fn = code + writetoexecdiff;
547 code = codeSnippet(
548 code, functionOffset++, vtableOffset, false);
550 break;
552 case typelib_TypeClass_INTERFACE_METHOD:
554 (s++)->fn = code + writetoexecdiff;
556 typelib_InterfaceMethodTypeDescription *pMethodTD =
557 reinterpret_cast<
558 typelib_InterfaceMethodTypeDescription * >(member);
560 code = codeSnippet(code, functionOffset++, vtableOffset,
561 arm::return_in_hidden_param(pMethodTD->pReturnTypeRef));
562 break;
564 default:
565 assert(false);
566 break;
568 TYPELIB_DANGER_RELEASE(member);
570 return code;
573 void bridges::cpp_uno::shared::VtableFactory::flushCode(
574 unsigned char const *beg, unsigned char const *end)
576 #ifndef ANDROID
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);
581 #else
582 cacheflush((long) beg, (long) end, 0);
583 #endif
586 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */