xref: /AOO41X/main/bridges/source/cpp_uno/gcc3_linux_arm/cpp2uno.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include <malloc.h>
29 #include <hash_map>
30 
31 #include <rtl/alloc.h>
32 #include <osl/mutex.hxx>
33 
34 #include <com/sun/star/uno/genfunc.hxx>
35 #include "com/sun/star/uno/RuntimeException.hpp"
36 #include <uno/data.h>
37 #include <typelib/typedescription.hxx>
38 
39 #include "bridges/cpp_uno/shared/bridge.hxx"
40 #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx"
41 #include "bridges/cpp_uno/shared/types.hxx"
42 #include "bridges/cpp_uno/shared/vtablefactory.hxx"
43 
44 #include "share.hxx"
45 
46 #include <dlfcn.h>
47 
48 
49 using namespace ::osl;
50 using namespace ::rtl;
51 using namespace ::com::sun::star::uno;
52 
53 namespace
54 {
55 
56     static typelib_TypeClass cpp2uno_call(
57         bridges::cpp_uno::shared::CppInterfaceProxy* pThis,
58         const typelib_TypeDescription * pMemberTypeDescr,
59         typelib_TypeDescriptionReference * pReturnTypeRef,
60         sal_Int32 nParams, typelib_MethodParameter * pParams,
61         void ** pCallStack,
62         sal_Int64 * pRegisterReturn /* space for register return */ )
63     {
64         // pCallStack: ret, [return ptr], this, params
65         char * pTopStack = (char *)(pCallStack + 0);
66         char * pCppStack = pTopStack;
67 
68         // return
69         typelib_TypeDescription * pReturnTypeDescr = 0;
70         if (pReturnTypeRef)
71             TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
72 
73         void * pUnoReturn = 0;
74         // complex return ptr: if != 0 && != pUnoReturn, reconversion need
75         void * pCppReturn = 0;
76 
77         if (pReturnTypeDescr)
78         {
79             if (!arm::return_in_hidden_param(pReturnTypeRef))
80                 pUnoReturn = pRegisterReturn; // direct way for simple types
81             else // complex return via ptr (pCppReturn)
82             {
83                 pCppReturn = *(void **)pCppStack;
84                 pCppStack += sizeof(void *);
85 
86                 pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType(
87                     pReturnTypeDescr )
88                         ? alloca( pReturnTypeDescr->nSize )
89                         : pCppReturn); // direct way
90             }
91         }
92         // pop this
93         pCppStack += sizeof( void* );
94 
95         // stack space
96         OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32),
97             "### unexpected size!" );
98         // parameters
99         void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams );
100         void ** pCppArgs = pUnoArgs + nParams;
101         // indizes of values this have to be converted (interface conversion
102         // cpp<=>uno)
103         sal_Int32 * pTempIndizes = (sal_Int32 *)(pUnoArgs + (2 * nParams));
104         // type descriptions for reconversions
105         typelib_TypeDescription ** ppTempParamTypeDescr =
106             (typelib_TypeDescription **)(pUnoArgs + (3 * nParams));
107 
108         sal_Int32 nTempIndizes   = 0;
109 
110         for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
111         {
112             const typelib_MethodParameter & rParam = pParams[nPos];
113             typelib_TypeDescription * pParamTypeDescr = 0;
114             TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
115 
116             if (!rParam.bOut &&
117                 bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
118             {
119 #ifdef __ARM_EABI__
120                 switch (pParamTypeDescr->eTypeClass)
121                 {
122                     case typelib_TypeClass_HYPER:
123                     case typelib_TypeClass_UNSIGNED_HYPER:
124                     case typelib_TypeClass_DOUBLE:
125 			if ((pCppStack - pTopStack) % 8) pCppStack+=sizeof(sal_Int32); //align to 8
126                         break;
127                     default:
128                         break;
129                 }
130 #endif
131 
132                 pCppArgs[nPos] = pCppStack;
133                 pUnoArgs[nPos] = pCppStack;
134                 switch (pParamTypeDescr->eTypeClass)
135                 {
136                     case typelib_TypeClass_HYPER:
137                     case typelib_TypeClass_UNSIGNED_HYPER:
138                     case typelib_TypeClass_DOUBLE:
139                         pCppStack += sizeof(sal_Int32); // extra long
140                         break;
141                     default:
142                         break;
143                 }
144                 // no longer needed
145                 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
146             }
147             else // ptr to complex value | ref
148             {
149                 pCppArgs[nPos] = *(void **)pCppStack;
150 
151                 if (! rParam.bIn) // is pure out
152                 {
153                     // uno out is unconstructed mem!
154                     pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
155                     pTempIndizes[nTempIndizes] = nPos;
156                     // will be released at reconversion
157                     ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
158                 }
159                 // is in/inout
160                 else if (bridges::cpp_uno::shared::relatesToInterfaceType(
161                     pParamTypeDescr ))
162                 {
163                     uno_copyAndConvertData( pUnoArgs[nPos] =
164                         alloca( pParamTypeDescr->nSize ),
165                         *(void **)pCppStack, pParamTypeDescr,
166                         pThis->getBridge()->getCpp2Uno() );
167                     pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
168                     // will be released at reconversion
169                     ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
170                 }
171                 else // direct way
172                 {
173                     pUnoArgs[nPos] = *(void **)pCppStack;
174                     // no longer needed
175                     TYPELIB_DANGER_RELEASE( pParamTypeDescr );
176                 }
177             }
178             pCppStack += sizeof(sal_Int32); // standard parameter length
179         }
180 
181         // ExceptionHolder
182         uno_Any aUnoExc; // Any will be constructed by callee
183         uno_Any * pUnoExc = &aUnoExc;
184 
185         // invoke uno dispatch call
186         (*pThis->getUnoI()->pDispatcher)(
187           pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
188 
189         // in case an exception occured...
190         if (pUnoExc)
191         {
192             // destruct temporary in/inout params
193             for ( ; nTempIndizes--; )
194             {
195                 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
196 
197                 if (pParams[nIndex].bIn) // is in/inout => was constructed
198                     uno_destructData( pUnoArgs[nIndex],
199                         ppTempParamTypeDescr[nTempIndizes], 0 );
200                 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
201             }
202             if (pReturnTypeDescr)
203                 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
204 
205             CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc,
206                 pThis->getBridge()->getUno2Cpp() ); // has to destruct the any
207             // is here for dummy
208             return typelib_TypeClass_VOID;
209         }
210         else // else no exception occured...
211         {
212             // temporary params
213             for ( ; nTempIndizes--; )
214             {
215                 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
216                 typelib_TypeDescription * pParamTypeDescr =
217                     ppTempParamTypeDescr[nTempIndizes];
218 
219                 if (pParams[nIndex].bOut) // inout/out
220                 {
221                     // convert and assign
222                     uno_destructData( pCppArgs[nIndex], pParamTypeDescr,
223                         cpp_release );
224                     uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex],
225                         pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
226                 }
227                 // destroy temp uno param
228                 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
229 
230                 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
231             }
232             // return
233             if (pCppReturn) // has complex return
234             {
235                 if (pUnoReturn != pCppReturn) // needs reconversion
236                 {
237                     uno_copyAndConvertData( pCppReturn, pUnoReturn,
238                         pReturnTypeDescr, pThis->getBridge()->getUno2Cpp() );
239                     // destroy temp uno return
240                     uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
241                 }
242                 // complex return ptr is set to eax
243                 *(void **)pRegisterReturn = pCppReturn;
244             }
245             if (pReturnTypeDescr)
246             {
247                 typelib_TypeClass eRet =
248                     (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
249                 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
250                 return eRet;
251             }
252             else
253                 return typelib_TypeClass_VOID;
254         }
255     }
256 
257 
258     //=====================================================================
259     static typelib_TypeClass cpp_mediate(
260         sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
261         void ** pCallStack,
262         sal_Int64 * pRegisterReturn /* space for register return */ )
263     {
264         OSL_ENSURE( sizeof(sal_Int32)==sizeof(void *), "### unexpected!" );
265 
266         // pCallStack: [ret *], this, params
267         // _this_ ptr is patched cppu_XInterfaceProxy object
268         void *pThis;
269         if( nFunctionIndex & 0x80000000 )
270         {
271             nFunctionIndex &= 0x7fffffff;
272             pThis = pCallStack[1];
273         }
274         else
275         {
276             pThis = pCallStack[0];
277         }
278 
279         pThis = static_cast< char * >(pThis) - nVtableOffset;
280         bridges::cpp_uno::shared::CppInterfaceProxy * pCppI =
281             bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
282                 pThis);
283 
284         typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
285 
286         OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex,
287             "### illegal vtable index!" );
288         if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
289         {
290             throw RuntimeException(
291                 OUString::createFromAscii("illegal vtable index!"),
292                 (XInterface *)pCppI );
293         }
294 
295         // determine called method
296         OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex,
297             "### illegal vtable index!" );
298         sal_Int32 nMemberPos =
299             pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
300         OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers,
301             "### illegal member index!" );
302 
303         TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
304 
305         typelib_TypeClass eRet;
306         switch (aMemberDescr.get()->eTypeClass)
307         {
308         case typelib_TypeClass_INTERFACE_ATTRIBUTE:
309         {
310             if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] ==
311                 nFunctionIndex)
312             {
313                 // is GET method
314                 eRet = cpp2uno_call(
315                     pCppI, aMemberDescr.get(),
316                     ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef,
317                     0, 0, // no params
318                     pCallStack, pRegisterReturn );
319             }
320             else
321             {
322                 // is SET method
323                 typelib_MethodParameter aParam;
324                 aParam.pTypeRef =
325                     ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef;
326                 aParam.bIn      = sal_True;
327                 aParam.bOut     = sal_False;
328 
329                 eRet = cpp2uno_call(
330                     pCppI, aMemberDescr.get(),
331                     0, // indicates void return
332                     1, &aParam,
333                     pCallStack, pRegisterReturn );
334             }
335             break;
336         }
337         case typelib_TypeClass_INTERFACE_METHOD:
338         {
339             // is METHOD
340             switch (nFunctionIndex)
341             {
342             case 1: // acquire()
343                 pCppI->acquireProxy(); // non virtual call!
344                 eRet = typelib_TypeClass_VOID;
345                 break;
346             case 2: // release()
347                 pCppI->releaseProxy(); // non virtual call!
348                 eRet = typelib_TypeClass_VOID;
349                 break;
350             case 0: // queryInterface() opt
351             {
352                 typelib_TypeDescription * pTD = 0;
353                 TYPELIB_DANGER_GET(&pTD,
354                     reinterpret_cast<Type *>(pCallStack[2])->getTypeLibType());
355                 if (pTD)
356                 {
357                     XInterface * pInterface = 0;
358                     (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
359                         pCppI->getBridge()->getCppEnv(),
360                         (void **)&pInterface, pCppI->getOid().pData,
361                         (typelib_InterfaceTypeDescription *)pTD );
362 
363                     if (pInterface)
364                     {
365                         ::uno_any_construct(
366                             reinterpret_cast< uno_Any * >( pCallStack[0] ),
367                             &pInterface, pTD, cpp_acquire );
368                         pInterface->release();
369                         TYPELIB_DANGER_RELEASE( pTD );
370                         *(void **)pRegisterReturn = pCallStack[0];
371                         eRet = typelib_TypeClass_ANY;
372                         break;
373                     }
374                     TYPELIB_DANGER_RELEASE( pTD );
375                 }
376             } // else perform queryInterface()
377             default:
378                 eRet = cpp2uno_call(
379                     pCppI, aMemberDescr.get(),
380                     ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef,
381                     ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams,
382                     ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams,
383                     pCallStack, pRegisterReturn );
384             }
385             break;
386         }
387         default:
388         {
389             throw RuntimeException(
390                 OUString::createFromAscii("no member description found!"),
391                 (XInterface *)pCppI );
392             // is here for dummy
393             eRet = typelib_TypeClass_VOID;
394         }
395         }
396 
397         return eRet;
398     }
399 }
400 
401 //=======================================================================
402 /**
403  * is called on incoming vtable calls
404  * (called by asm snippets)
405  */
406 
407 extern "C" sal_Int64 cpp_vtable_call( long *pFunctionAndOffset,
408     void **pCallStack )
409 {
410     sal_Int64 nRegReturn;
411     typelib_TypeClass aType = cpp_mediate( pFunctionAndOffset[0], pFunctionAndOffset[1], pCallStack,
412         &nRegReturn );
413 
414     switch( aType )
415     {
416         case typelib_TypeClass_BOOLEAN:
417         case typelib_TypeClass_BYTE:
418             nRegReturn = (unsigned long)(*(unsigned char *)&nRegReturn);
419             break;
420         case typelib_TypeClass_CHAR:
421         case typelib_TypeClass_UNSIGNED_SHORT:
422         case typelib_TypeClass_SHORT:
423             nRegReturn = (unsigned long)(*(unsigned short *)&nRegReturn);
424             break;
425         case typelib_TypeClass_ENUM:
426         case typelib_TypeClass_UNSIGNED_LONG:
427         case typelib_TypeClass_LONG:
428             nRegReturn = (unsigned long)(*(unsigned int *)&nRegReturn);
429             break;
430         case typelib_TypeClass_VOID:
431         default:
432             break;
433     }
434 
435     return nRegReturn;
436 }
437 
438 extern "C" void privateSnippetExecutor(void);
439 
440 namespace
441 {
442     const int codeSnippetSize = 20;
443 
444     unsigned char *codeSnippet(unsigned char* code, sal_Int32 functionIndex,
445         sal_Int32 vtableOffset, bool bHasHiddenParam)
446     {
447         if (bHasHiddenParam)
448             functionIndex |= 0x80000000;
449 
450         unsigned long * p = (unsigned long *)code;
451 
452         *p++ = 0xE1A0C00F;
453         *p++ = 0xE59FF004;
454         *p++ = (unsigned long)functionIndex;
455         *p++ = (unsigned long)vtableOffset;
456         *p++ = (unsigned long)privateSnippetExecutor;
457 
458         return code + codeSnippetSize;
459     }
460 }
461 
462 struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; };
463 
464 bridges::cpp_uno::shared::VtableFactory::Slot *
465 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
466 {
467     return static_cast< Slot * >(block) + 2;
468 }
469 
470 sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize(
471     sal_Int32 slotCount)
472 {
473     return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
474 }
475 
476 bridges::cpp_uno::shared::VtableFactory::Slot *
477 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
478     void * block, sal_Int32 slotCount)
479 {
480     Slot * slots = mapBlockToVtable(block);
481     slots[-2].fn = 0;
482     slots[-1].fn = 0;
483     return slots + slotCount;
484 }
485 
486 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
487     Slot ** slots, unsigned char * code, sal_PtrDiff writetoexecdiff,
488     typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
489     sal_Int32 functionCount, sal_Int32 vtableOffset)
490 {
491     (*slots) -= functionCount;
492     Slot * s = *slots;
493     for (sal_Int32 i = 0; i < type->nMembers; ++i)
494     {
495         typelib_TypeDescription * member = 0;
496         TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
497         OSL_ASSERT(member != 0);
498         switch (member->eTypeClass)
499         {
500             case typelib_TypeClass_INTERFACE_ATTRIBUTE:
501             {
502                 typelib_InterfaceAttributeTypeDescription *pAttrTD =
503                     reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( member );
504 
505                 // Getter:
506                 (s++)->fn = code + writetoexecdiff;
507                 code = codeSnippet(
508                     code, functionOffset++, vtableOffset,
509                     arm::return_in_hidden_param( pAttrTD->pAttributeTypeRef ));
510 
511                 // Setter:
512                 if (!pAttrTD->bReadOnly)
513                 {
514                     (s++)->fn = code + writetoexecdiff;
515                     code = codeSnippet(
516                         code, functionOffset++, vtableOffset, false);
517                 }
518                 break;
519             }
520             case typelib_TypeClass_INTERFACE_METHOD:
521             {
522                 (s++)->fn = code + writetoexecdiff;
523 
524                 typelib_InterfaceMethodTypeDescription *pMethodTD =
525                     reinterpret_cast<
526                         typelib_InterfaceMethodTypeDescription * >(member);
527 
528                 code = codeSnippet(code, functionOffset++, vtableOffset,
529                     arm::return_in_hidden_param(pMethodTD->pReturnTypeRef));
530                 break;
531             }
532         default:
533             OSL_ASSERT(false);
534             break;
535         }
536         TYPELIB_DANGER_RELEASE(member);
537     }
538     return code;
539 }
540 
541 void bridges::cpp_uno::shared::VtableFactory::flushCode(
542     unsigned char const *beg, unsigned char const *end)
543 {
544    static void (*clear_cache)(unsigned char const*, unsigned char const*)
545        = (void (*)(unsigned char const*, unsigned char const*))
546            dlsym(RTLD_DEFAULT, "__clear_cache");
547    (*clear_cache)(beg, end);
548 }
549 
550 /* vi:set tabstop=4 shiftwidth=4 expandtab: */
551