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 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_bridges.hxx"
30 
31 #include <malloc.h>
32 
33 #include <com/sun/star/uno/genfunc.hxx>
34 #include <uno/data.h>
35 
36 #include "bridges/cpp_uno/shared/bridge.hxx"
37 #include "bridges/cpp_uno/shared/types.hxx"
38 #include "bridges/cpp_uno/shared/unointerfaceproxy.hxx"
39 #include "bridges/cpp_uno/shared/vtables.hxx"
40 
41 #include "share.hxx"
42 
43 #include <stdio.h>
44 #include <string.h>
45 
46 
47 using namespace ::rtl;
48 using namespace ::com::sun::star::uno;
49 
50 void MapReturn(long r0, typelib_TypeClass eTypeClass, sal_uInt64* pRegisterReturn)
51 {
52     register float fret asm("$f0");
53     register double dret asm("$f0");
54 
55 #ifdef CMC_DEBUG
56     fprintf(stderr,"Mapping Return with %lx %ld %f\n", r0, r0, dret);
57 #endif
58     switch (eTypeClass)
59     {
60     case typelib_TypeClass_HYPER:
61     case typelib_TypeClass_UNSIGNED_HYPER:
62             *pRegisterReturn = r0;
63             break;
64     case typelib_TypeClass_LONG:
65     case typelib_TypeClass_UNSIGNED_LONG:
66     case typelib_TypeClass_ENUM:
67             *(unsigned int*)pRegisterReturn = (unsigned int)r0;
68             break;
69     case typelib_TypeClass_CHAR:
70     case typelib_TypeClass_SHORT:
71     case typelib_TypeClass_UNSIGNED_SHORT:
72             *(unsigned short*)pRegisterReturn = (unsigned short)r0;
73             break;
74     case typelib_TypeClass_BOOLEAN:
75     case typelib_TypeClass_BYTE:
76             *(unsigned char*)pRegisterReturn = (unsigned char)r0;
77             break;
78     case typelib_TypeClass_FLOAT:
79             *reinterpret_cast<float *>( pRegisterReturn ) = fret;
80             break;
81     case typelib_TypeClass_DOUBLE:
82             *reinterpret_cast<double *>( pRegisterReturn ) = dret;
83             break;
84     default:
85             break;
86     }
87 #ifdef CMC_DEBUG
88     fprintf(stderr, "end of MapReturn with %x\n", pRegisterReturn ? *pRegisterReturn : 0);
89 #endif
90 }
91 
92 #define INSERT_FLOAT( pSV, nr, pFPR, pDS ) \
93     { \
94         if ( nr < axp::MAX_WORDS_IN_REGS ) \
95         { \
96                 pFPR[nr++] = *reinterpret_cast<float *>( pSV ); \
97         } \
98         else \
99                 *pDS++ = *reinterpret_cast<sal_uInt64 *>( pSV ); \
100     }
101 
102 #define INSERT_DOUBLE( pSV, nr, pFPR, pDS ) \
103         if ( nr < axp::MAX_WORDS_IN_REGS ) \
104                 pFPR[nr++] = *reinterpret_cast<double *>( pSV ); \
105         else \
106                 *pDS++ = *reinterpret_cast<sal_uInt64 *>( pSV ); // verbatim!
107 
108 #define INSERT_INT64( pSV, nr, pGPR, pDS ) \
109         if ( nr < axp::MAX_WORDS_IN_REGS ) \
110                 pGPR[nr++] = *reinterpret_cast<sal_uInt64 *>( pSV ); \
111         else \
112                 *pDS++ = *reinterpret_cast<sal_uInt64 *>( pSV );
113 
114 #define INSERT_INT32( pSV, nr, pGPR, pDS ) \
115         if ( nr < axp::MAX_WORDS_IN_REGS ) \
116                 pGPR[nr++] = *reinterpret_cast<sal_uInt32 *>( pSV ); \
117         else \
118                 *pDS++ = *reinterpret_cast<sal_uInt32 *>( pSV );
119 
120 #define INSERT_INT16( pSV, nr, pGPR, pDS ) \
121         if ( nr < axp::MAX_WORDS_IN_REGS ) \
122                 pGPR[nr++] = *reinterpret_cast<sal_uInt16 *>( pSV ); \
123         else \
124                 *pDS++ = *reinterpret_cast<sal_uInt16 *>( pSV );
125 
126 #define INSERT_INT8( pSV, nr, pGPR, pDS ) \
127         if ( nr < axp::MAX_WORDS_IN_REGS ) \
128                 pGPR[nr++] = *reinterpret_cast<sal_uInt8 *>( pSV ); \
129         else \
130                 *pDS++ = *reinterpret_cast<sal_uInt8 *>( pSV );
131 
132 namespace
133 {
134 //==================================================================================================
135 void callVirtualMethod(
136     void * pThis, sal_Int32 nVtableIndex,
137     void * pRegisterReturn, typelib_TypeDescription * pReturnTypeDescr,
138     sal_uInt64 *pStack, sal_uInt32 nStack,
139     sal_uInt64 *pGPR, sal_uInt32 nGPR,
140     double *pFPR, sal_uInt32 nFPR)
141 {
142     // Should not happen, but...
143     if ( nFPR > axp::MAX_SSE_REGS )
144         nFPR = axp::MAX_SSE_REGS;
145     if ( nGPR > axp::MAX_GPR_REGS )
146         nGPR = axp::MAX_GPR_REGS;
147 
148 #ifdef CMC_DEBUG
149         // Let's figure out what is really going on here
150         {
151             fprintf( stderr, "= nStack is %d\n", nStack );
152             fprintf( stderr, "= callVirtualMethod() =\nGPR's (%d): ", nGPR );
153             for ( unsigned int i = 0; i < nGPR; ++i )
154                 fprintf( stderr, "0x%lx, ", pGPR[i] );
155             fprintf( stderr, "\nFPR's (%d): ", nFPR );
156             for ( unsigned int i = 0; i < nFPR; ++i )
157                 fprintf( stderr, "0x%lx (%f), ", pFPR[i], pFPR[i] );
158             fprintf( stderr, "\nStack (%d): ", nStack );
159             for ( unsigned int i = 0; i < nStack; ++i )
160                 fprintf( stderr, "0x%lx, ", pStack[i] );
161             fprintf( stderr, "\n" );
162             fprintf( stderr, "pRegisterReturn is %p\n", pRegisterReturn);
163         }
164 #endif
165 
166     // Load parameters to stack, if necessary
167     // Stack, if used, must be 8-bytes aligned
168     sal_uInt64 *stack = (sal_uInt64 *) __builtin_alloca( nStack * 8 );
169     memcpy( stack, pStack, nStack * 8 );
170 
171     // To get pointer to method
172     // a) get the address of the vtable
173     sal_uInt64 pMethod = *((sal_uInt64 *)pThis);
174     // b) get the address from the vtable entry at offset
175     pMethod += 8 * nVtableIndex;
176     pMethod = *((sal_uInt64 *)pMethod);
177 
178     typedef void (* FunctionCall )( sal_uInt64, sal_uInt64, sal_uInt64, sal_uInt64, sal_uInt64, sal_uInt64 );
179     FunctionCall pFunc = (FunctionCall)pMethod;
180 
181     switch (nFPR) //deliberate fall through
182     {
183         case 6:
184             asm volatile("ldt $f16,%0" :: "m"(pFPR[5]) : "$f16");
185         case 5:
186             asm volatile("ldt $f17,%0" :: "m"(pFPR[4]) : "$f17");
187         case 4:
188             asm volatile("ldt $f18,%0" :: "m"(pFPR[3]) : "$f18");
189         case 3:
190             asm volatile("ldt $f19,%0" :: "m"(pFPR[2]) : "$f19");
191         case 2:
192             asm volatile("ldt $f20,%0" :: "m"(pFPR[1]) : "$f20");
193         case 1:
194             asm volatile("ldt $f21,%0" :: "m"(pFPR[0]) : "$f21");
195         default:
196             break;
197     }
198 
199     (*pFunc)(pGPR[0], pGPR[1], pGPR[2], pGPR[3], pGPR[4], pGPR[5]);
200     register sal_uInt64 r0 __asm__("$0");
201     MapReturn(r0, pReturnTypeDescr->eTypeClass, (sal_uInt64*)pRegisterReturn);
202 }
203 
204 
205 //============================================================================
206 static void cpp_call(
207         bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
208         bridges::cpp_uno::shared::VtableSlot  aVtableSlot,
209         typelib_TypeDescriptionReference * pReturnTypeRef,
210     sal_Int32 nParams, typelib_MethodParameter * pParams,
211     void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
212 {
213     // max space for: [complex ret ptr], values|ptr ...
214     sal_uInt64 * pStack = (sal_uInt64 *)alloca( (nParams+3) * sizeof(sal_Int64) );
215     sal_uInt64 * pStackStart = pStack;
216 
217     sal_uInt64 pGPR[axp::MAX_GPR_REGS];
218     double pFPR[axp::MAX_SSE_REGS];
219     sal_uInt32 nRegs = 0;
220 
221     // return
222     typelib_TypeDescription * pReturnTypeDescr = 0;
223     TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
224     OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" );
225 
226     void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
227 
228     if (pReturnTypeDescr)
229     {
230         if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr ))
231         {
232             pCppReturn = pUnoReturn; // direct way for simple types
233         }
234         else
235         {
236             // complex return via ptr
237             pCppReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
238                                                 ? alloca( pReturnTypeDescr->nSize )
239                                                 : pUnoReturn); // direct way
240             INSERT_INT64( &pCppReturn, nRegs, pGPR, pStack );
241         }
242     }
243         // push "this" pointer
244     void * pAdjustedThisPtr = reinterpret_cast< void ** >( pThis->getCppI() ) + aVtableSlot.offset;
245 
246     INSERT_INT64( &pAdjustedThisPtr, nRegs, pGPR, pStack );
247 
248     // stack space
249     OSL_ENSURE( sizeof(void *) == sizeof(sal_Int64), "### unexpected size!" );
250     // args
251     void ** pCppArgs  = (void **)alloca( 3 * sizeof(void *) * nParams );
252     // indizes of values this have to be converted (interface conversion cpp<=>uno)
253     sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams);
254     // type descriptions for reconversions
255     typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
256 
257     sal_Int32 nTempIndizes   = 0;
258 
259     for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
260     {
261         const typelib_MethodParameter & rParam = pParams[nPos];
262         typelib_TypeDescription * pParamTypeDescr = 0;
263         TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
264 
265         if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
266         {
267             uno_copyAndConvertData( pCppArgs[nPos] = alloca( 8 ), pUnoArgs[nPos], pParamTypeDescr,
268                                     pThis->getBridge()->getUno2Cpp() );
269 
270             switch (pParamTypeDescr->eTypeClass)
271             {
272                 case typelib_TypeClass_HYPER:
273                 case typelib_TypeClass_UNSIGNED_HYPER:
274                     INSERT_INT64( pCppArgs[nPos], nRegs, pGPR, pStack );
275                     break;
276                 case typelib_TypeClass_LONG:
277                 case typelib_TypeClass_UNSIGNED_LONG:
278                 case typelib_TypeClass_ENUM:
279                     INSERT_INT32( pCppArgs[nPos], nRegs, pGPR, pStack );
280                     break;
281                 case typelib_TypeClass_SHORT:
282                 case typelib_TypeClass_CHAR:
283                 case typelib_TypeClass_UNSIGNED_SHORT:
284                     INSERT_INT16( pCppArgs[nPos], nRegs, pGPR, pStack );
285                     break;
286                 case typelib_TypeClass_BOOLEAN:
287                 case typelib_TypeClass_BYTE:
288                     INSERT_INT8( pCppArgs[nPos], nRegs, pGPR, pStack );
289                     break;
290                 case typelib_TypeClass_FLOAT:
291                     INSERT_FLOAT( pCppArgs[nPos], nRegs, pFPR, pStack );
292                     break;
293                 case typelib_TypeClass_DOUBLE:
294                     INSERT_DOUBLE( pCppArgs[nPos], nRegs, pFPR, pStack );
295                     break;
296                 default:
297                     break;
298             }
299 
300             // no longer needed
301             TYPELIB_DANGER_RELEASE( pParamTypeDescr );
302         }
303         else // ptr to complex value | ref
304         {
305             if (! rParam.bIn) // is pure out
306             {
307                 // cpp out is constructed mem, uno out is not!
308                 uno_constructData(
309                     pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
310                     pParamTypeDescr );
311                 pTempIndizes[nTempIndizes] = nPos; // default constructed for cpp call
312                 // will be released at reconversion
313                 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
314             }
315             // is in/inout
316             else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
317             {
318                 uno_copyAndConvertData(
319                     pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
320                     pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
321 
322                 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
323                 // will be released at reconversion
324                 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
325             }
326             else // direct way
327             {
328                 pCppArgs[nPos] = pUnoArgs[nPos];
329                 // no longer needed
330                 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
331             }
332             INSERT_INT64( &(pCppArgs[nPos]), nRegs, pGPR, pStack );
333         }
334     }
335 
336     try
337     {
338         callVirtualMethod(
339             pAdjustedThisPtr, aVtableSlot.index,
340             pCppReturn, pReturnTypeDescr,
341             pStackStart, (pStack - pStackStart),
342             pGPR, nRegs,
343             pFPR, nRegs );
344         // NO exception occured...
345         *ppUnoExc = 0;
346 
347         // reconvert temporary params
348         for ( ; nTempIndizes--; )
349         {
350             sal_Int32 nIndex = pTempIndizes[nTempIndizes];
351             typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
352 
353             if (pParams[nIndex].bIn)
354             {
355                 if (pParams[nIndex].bOut) // inout
356                 {
357                     uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
358                     uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
359                                             pThis->getBridge()->getCpp2Uno() );
360                 }
361             }
362             else // pure out
363             {
364                 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
365                                         pThis->getBridge()->getCpp2Uno() );
366             }
367             // destroy temp cpp param => cpp: every param was constructed
368             uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
369 
370             TYPELIB_DANGER_RELEASE( pParamTypeDescr );
371         }
372         // return value
373         if (pCppReturn && pUnoReturn != pCppReturn)
374         {
375             uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
376                                     pThis->getBridge()->getCpp2Uno() );
377             uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
378         }
379     }
380     catch (...)
381     {
382         // fill uno exception
383         fillUnoException( CPPU_CURRENT_NAMESPACE::__cxa_get_globals()->caughtExceptions,
384             *ppUnoExc, pThis->getBridge()->getCpp2Uno() );
385 
386 
387         // temporary params
388         for ( ; nTempIndizes--; )
389         {
390             sal_Int32 nIndex = pTempIndizes[nTempIndizes];
391             // destroy temp cpp param => cpp: every param was constructed
392             uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], cpp_release );
393             TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
394         }
395         // return type
396         if (pReturnTypeDescr)
397             TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
398     }
399 }
400 }
401 
402 namespace bridges { namespace cpp_uno { namespace shared {
403 
404 void unoInterfaceProxyDispatch(
405     uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
406     void * pReturn, void * pArgs[], uno_Any ** ppException )
407 {
408 #ifdef CMC_DEBUG
409     fprintf(stderr, "unoInterfaceProxyDispatch\n");
410 #endif
411 
412 
413     // is my surrogate
414     bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
415             = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy *> (pUnoI);
416 
417     switch (pMemberDescr->eTypeClass)
418     {
419     case typelib_TypeClass_INTERFACE_ATTRIBUTE:
420     {
421 
422         VtableSlot aVtableSlot(
423             getVtableSlot(
424                 reinterpret_cast<
425                     typelib_InterfaceAttributeTypeDescription const * >(
426                         pMemberDescr)));
427 
428         if (pReturn)
429         {
430             // dependent dispatch
431             cpp_call(
432                 pThis, aVtableSlot,
433                 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
434                 0, 0, // no params
435                 pReturn, pArgs, ppException );
436         }
437         else
438         {
439             // is SET
440             typelib_MethodParameter aParam;
441             aParam.pTypeRef =
442                 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
443             aParam.bIn      = sal_True;
444             aParam.bOut     = sal_False;
445 
446             typelib_TypeDescriptionReference * pReturnTypeRef = 0;
447             OUString aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") );
448             typelib_typedescriptionreference_new(
449                 &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
450 
451             // dependent dispatch
452                         aVtableSlot.index += 1; //get then set method
453             cpp_call(
454                 pThis, aVtableSlot,
455                 pReturnTypeRef,
456                 1, &aParam,
457                 pReturn, pArgs, ppException );
458 
459             typelib_typedescriptionreference_release( pReturnTypeRef );
460         }
461 
462         break;
463     }
464     case typelib_TypeClass_INTERFACE_METHOD:
465     {
466 
467         VtableSlot aVtableSlot(
468             getVtableSlot(
469                 reinterpret_cast<
470                     typelib_InterfaceMethodTypeDescription const * >(
471                         pMemberDescr)));
472         switch (aVtableSlot.index)
473         {
474             // standard calls
475         case 1: // acquire uno interface
476             (*pUnoI->acquire)( pUnoI );
477             *ppException = 0;
478             break;
479         case 2: // release uno interface
480             (*pUnoI->release)( pUnoI );
481             *ppException = 0;
482             break;
483         case 0: // queryInterface() opt
484         {
485             typelib_TypeDescription * pTD = 0;
486             TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() );
487             if (pTD)
488             {
489                 uno_Interface * pInterface = 0;
490                 (*pThis->pBridge->getUnoEnv()->getRegisteredInterface)(
491                     pThis->pBridge->getUnoEnv(),
492                     (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
493 
494                 if (pInterface)
495                 {
496                     ::uno_any_construct(
497                         reinterpret_cast< uno_Any * >( pReturn ),
498                         &pInterface, pTD, 0 );
499                     (*pInterface->release)( pInterface );
500                     TYPELIB_DANGER_RELEASE( pTD );
501                     *ppException = 0;
502                     break;
503                 }
504                 TYPELIB_DANGER_RELEASE( pTD );
505             }
506         } // else perform queryInterface()
507         default:
508             // dependent dispatch
509             cpp_call(
510                 pThis, aVtableSlot,
511                 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef,
512                 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams,
513                 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams,
514                 pReturn, pArgs, ppException );
515         }
516         break;
517     }
518     default:
519     {
520         ::com::sun::star::uno::RuntimeException aExc(
521             OUString( RTL_CONSTASCII_USTRINGPARAM("illegal member type description!") ),
522             ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
523 
524         Type const & rExcType = ::getCppuType( &aExc );
525         // binary identical null reference
526         ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
527     }
528     }
529 }
530 
531 } } }
532 /* vi:set tabstop=4 shiftwidth=4 expandtab: */
533