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