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