xref: /trunk/main/bridges/source/cpp_uno/gcc3_linux_mips/uno2cpp.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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 
30 #include <com/sun/star/uno/genfunc.hxx>
31 #include <uno/data.h>
32 
33 #include "bridges/cpp_uno/shared/bridge.hxx"
34 #include "bridges/cpp_uno/shared/types.hxx"
35 #include "bridges/cpp_uno/shared/unointerfaceproxy.hxx"
36 #include "bridges/cpp_uno/shared/vtables.hxx"
37 
38 #include "share.hxx"
39 
40 //#define BRDEBUG
41 #ifdef BRDEBUG
42 #include <stdio.h>
43 #endif
44 
45 
46 using namespace ::rtl;
47 using namespace ::com::sun::star::uno;
48 
49 namespace
50 {
51 
52 
53   //==================================================================================================
54   static void callVirtualMethod(
55       void * pAdjustedThisPtr,
56       sal_Int32 nVtableIndex,
57       void * pRegisterReturn,
58       typelib_TypeClass eReturnType,
59       char * pPT,
60       sal_Int32 * pStackLongs,
61       sal_Int32 /*nStackLongs*/)
62   {
63 
64     // parameter list is mixed list of * and values
65     // reference parameters are pointers
66 
67     unsigned long * mfunc;        // actual function to be invoked
68     void (*ptr)();
69     int gpr[4];                   // storage for gpregisters, map to a0-a3
70     int off;                      // offset used to find function
71     int nw;                       // number of words mapped
72     long *p;                      // pointer to parameter overflow area
73     int c;                        // character of parameter type being decoded
74     int iret, iret2;              // temporary function return values
75 
76     // never called
77     if (! pAdjustedThisPtr ) CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything("xxx"); // address something
78 
79 #ifdef BRDEBUG
80     fprintf(stderr,"in CallVirtualMethod\n");
81 #endif
82 
83     // Because of the MIPS O32 calling conventions we could be passing
84     // parameters in both register types and on the stack. To create the
85     // stack parameter area we need we now simply allocate local
86     // variable storage param[] that is at least the size of the parameter stack
87     // (more than enough space) which we can overwrite the parameters into.
88 
89     /* p = sp - 512; new sp will be p - 16, but we don't change sp
90      * at this time to avoid breaking ABI--not sure whether changing sp will break
91      * references to local variables. For the same reason, we use abosulte value.
92      */
93     __asm__ __volatile__ (
94         "addiu $2,$29,-512\n\t"
95         "move %0,$2\n\t"
96         :"=r"(p): : "$2","$29" );
97 
98 #ifdef BRDEBUG
99      if (nStackLongs * 4 > 512 )
100          fprintf(stderr,"too many arguments");
101 #endif
102 
103     // now begin to load the C++ function arguments into storage
104     nw = 0;
105 
106     // now we need to parse the entire signature string */
107     // until we get the END indicator */
108 
109     // treat complex return pointer like any other parameter //
110 
111 #ifdef BRDEBUG
112     fprintf(stderr,"overflow area pointer p=%p\n",p);
113 
114     /* Let's figure out what is really going on here*/
115     fprintf(stderr,"callVirtualMethod paramters string is %s\n",pPT);
116     int k = nStackLongs;
117     long * q = (long *)pStackLongs;
118     while (k > 0) {
119       fprintf(stderr,"uno stack is: %x\n",(unsigned int)*q);
120       k--;
121       q++;
122     }
123 #endif
124 
125     /* parse the argument list up to the ending ) */
126     while (*pPT != 'X') {
127       c = *pPT;
128       switch (c) {
129         case 'D':                   /* type is double */
130           /* treat the same as long long */
131         case 'H':                /* type is long long */
132           if (nw & 1) nw++;     /* note even elements gpr[] will map to
133                                odd registers*/
134           if (nw < 4) {
135             gpr[nw++] = *pStackLongs;
136             gpr[nw++] = *(pStackLongs+1);
137           } else {
138             if (((long) p) & 4)
139               p++;
140             *p++ = *pStackLongs;
141             *p++ = *(pStackLongs+1);
142           }
143           pStackLongs += 2;
144           break;
145 
146         case 'S':
147           if (nw < 4) {
148             gpr[nw++] = *((unsigned short*)pStackLongs);
149           } else {
150             *p++ = *((unsigned short *)pStackLongs);
151           }
152           pStackLongs += 1;
153           break;
154 
155         case 'B':
156           if (nw < 4) {
157             gpr[nw++] = *((char *)pStackLongs);
158           } else {
159             *p++ = *((char *)pStackLongs);
160           }
161           pStackLongs += 1;
162           break;
163 
164         default:
165           if (nw < 4) {
166             gpr[nw++] = *pStackLongs;
167           } else {
168             *p++ = *pStackLongs;
169           }
170           pStackLongs += 1;
171           break;
172       }
173       pPT++;
174     }
175 
176     /* figure out the address of the function we need to invoke */
177     off = nVtableIndex;
178     off = off * 4;                         // 4 bytes per slot
179     mfunc = *((unsigned long **)pAdjustedThisPtr);    // get the address of the vtable
180     mfunc = (unsigned long *)((char *)mfunc + off); // get the address from the vtable entry at offset
181     mfunc = *((unsigned long **)mfunc);                 // the function is stored at the address
182     ptr = (void (*)())mfunc;
183 
184 #ifdef BRDEBUG
185     fprintf(stderr,"calling function %p\n",mfunc);
186 #endif
187 
188     /* Set up the machine registers and invoke the function */
189 
190     __asm__ __volatile__ (
191         "lw $4, 0(%0)\n\t"
192         "lw $5, 4(%0)\n\t"
193         "lw $6, 8(%0)\n\t"
194         "lw $7, 12(%0)\n\t"
195         : : "r" (gpr)
196         : "$4", "$5", "$6", "$7"
197         );
198 
199     __asm__ __volatile__ ("addiu $29,$29,-528\r\n":::"$29");
200 
201     (*ptr)();
202 
203     __asm__ __volatile__ ("addiu $29,$29,528\r\n":::"$29");
204 
205     __asm__ __volatile__ (
206         "sw $2,%0 \n\t"
207         "sw $3,%1 \n\t"
208         : "=m" (iret), "=m" (iret2) : );
209     register float fret asm("$f0");
210     register double dret asm("$f0");
211 
212     switch( eReturnType )
213     {
214       case typelib_TypeClass_HYPER:
215       case typelib_TypeClass_UNSIGNED_HYPER:
216         ((long*)pRegisterReturn)[1] = iret2;    // fall through
217       case typelib_TypeClass_LONG:
218       case typelib_TypeClass_UNSIGNED_LONG:
219       case typelib_TypeClass_ENUM:
220         ((long*)pRegisterReturn)[0] = iret;
221         break;
222       case typelib_TypeClass_CHAR:
223       case typelib_TypeClass_SHORT:
224       case typelib_TypeClass_UNSIGNED_SHORT:
225         *(unsigned short*)pRegisterReturn = (unsigned short)iret;
226         break;
227       case typelib_TypeClass_BOOLEAN:
228       case typelib_TypeClass_BYTE:
229         *(unsigned char*)pRegisterReturn = (unsigned char)iret;
230         break;
231       case typelib_TypeClass_FLOAT:
232         *(float*)pRegisterReturn = fret;
233         break;
234       case typelib_TypeClass_DOUBLE:
235         *(double*)pRegisterReturn = dret;
236         break;
237       default:
238         break;
239     }
240   }
241 
242 
243   //==================================================================================================
244   static void cpp_call(
245       bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
246       bridges::cpp_uno::shared::VtableSlot  aVtableSlot,
247       typelib_TypeDescriptionReference * pReturnTypeRef,
248       sal_Int32 nParams, typelib_MethodParameter * pParams,
249       void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
250   {
251     // max space for: [complex ret ptr], values|ptr ...
252     char * pCppStack        =
253       (char *)alloca( sizeof(sal_Int32) + ((nParams+2) * sizeof(sal_Int64)) );
254     char * pCppStackStart   = pCppStack;
255 
256     // need to know parameter types for callVirtualMethod so generate a signature string
257     char * pParamType = (char *) alloca(nParams+2);
258     char * pPT = pParamType;
259 
260 #ifdef BRDEBUG
261   fprintf(stderr,"in cpp_call\n");
262 #endif
263 
264     // return
265     typelib_TypeDescription * pReturnTypeDescr = 0;
266     TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
267     // OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" );
268 
269     void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
270 
271     if (pReturnTypeDescr)
272     {
273       if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr ))
274       {
275         pCppReturn = pUnoReturn; // direct way for simple types
276       }
277       else
278       {
279         // complex return via ptr
280         pCppReturn = *(void **)pCppStack =
281           (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
282            ? alloca( pReturnTypeDescr->nSize ): pUnoReturn); // direct way
283         *pPT++ = 'I'; //signify that a complex return type on stack
284         pCppStack += sizeof(void *);
285       }
286     }
287     // push this
288     void* pAdjustedThisPtr = reinterpret_cast< void **>(pThis->getCppI()) + aVtableSlot.offset;
289     *(void**)pCppStack = pAdjustedThisPtr;
290     pCppStack += sizeof( void* );
291     *pPT++ = 'I';
292 
293     // stack space
294     // OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" );
295     // args
296     void ** pCppArgs  = (void **)alloca( 3 * sizeof(void *) * nParams );
297     // indizes of values this have to be converted (interface conversion cpp<=>uno)
298     sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams);
299     // type descriptions for reconversions
300     typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
301 
302     sal_Int32 nTempIndizes   = 0;
303 
304     for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
305     {
306       const typelib_MethodParameter & rParam = pParams[nPos];
307       typelib_TypeDescription * pParamTypeDescr = 0;
308       TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
309 
310       if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
311       {
312         uno_copyAndConvertData( pCppArgs[nPos] = pCppStack, pUnoArgs[nPos], pParamTypeDescr,
313             pThis->getBridge()->getUno2Cpp() );
314 
315         switch (pParamTypeDescr->eTypeClass)
316         {
317 
318           // we need to know type of each param so that we know whether to use
319           // gpr or fpr to pass in parameters:
320           // Key: I - int, long, pointer, etc means pass in gpr
321           //      B - byte value passed in gpr
322           //      S - short value passed in gpr
323           //      F - float value pass in fpr
324           //      D - double value pass in fpr
325           //      H - long long int pass in proper pairs of gpr (3,4) (5,6), etc
326           //      X - indicates end of parameter description string
327 
328           case typelib_TypeClass_LONG:
329           case typelib_TypeClass_UNSIGNED_LONG:
330           case typelib_TypeClass_ENUM:
331             *pPT++ = 'I';
332             break;
333           case typelib_TypeClass_SHORT:
334           case typelib_TypeClass_CHAR:
335           case typelib_TypeClass_UNSIGNED_SHORT:
336             *pPT++ = 'S';
337             break;
338           case typelib_TypeClass_BOOLEAN:
339           case typelib_TypeClass_BYTE:
340             *pPT++ = 'B';
341             break;
342           case typelib_TypeClass_FLOAT:
343             *pPT++ = 'F';
344             break;
345           case typelib_TypeClass_DOUBLE:
346             *pPT++ = 'D';
347             pCppStack += sizeof(sal_Int32); // extra long
348             break;
349           case typelib_TypeClass_HYPER:
350           case typelib_TypeClass_UNSIGNED_HYPER:
351             *pPT++ = 'H';
352             pCppStack += sizeof(sal_Int32); // extra long
353             break;
354           default:
355             break;
356         }
357 
358         // no longer needed
359         TYPELIB_DANGER_RELEASE( pParamTypeDescr );
360       }
361       else // ptr to complex value | ref
362       {
363         if (! rParam.bIn) // is pure out
364         {
365           // cpp out is constructed mem, uno out is not!
366           uno_constructData(
367               *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
368               pParamTypeDescr );
369           pTempIndizes[nTempIndizes] = nPos; // default constructed for cpp call
370           // will be released at reconversion
371           ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
372         }
373         // is in/inout
374         else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
375         {
376           uno_copyAndConvertData(
377               *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
378               pUnoArgs[nPos], pParamTypeDescr,
379               pThis->getBridge()->getUno2Cpp() );
380 
381           pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
382           // will be released at reconversion
383           ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
384         }
385         else // direct way
386         {
387           *(void **)pCppStack = pCppArgs[nPos] = pUnoArgs[nPos];
388           // no longer needed
389           TYPELIB_DANGER_RELEASE( pParamTypeDescr );
390         }
391         // KBH: FIXME: is this the right way to pass these
392         *pPT++='I';
393       }
394       pCppStack += sizeof(sal_Int32); // standard parameter length
395     }
396 
397     // terminate the signature string
398     *pPT++='X';
399     *pPT=0;
400 
401     try
402     {
403       OSL_ENSURE( !( (pCppStack - pCppStackStart ) & 3), "UNALIGNED STACK !!! (Please DO panic)" );
404       callVirtualMethod(
405           pAdjustedThisPtr, aVtableSlot.index,
406           pCppReturn, pReturnTypeDescr->eTypeClass, pParamType,
407           (sal_Int32 *)pCppStackStart, (pCppStack - pCppStackStart) / sizeof(sal_Int32) );
408       // NO exception occured...
409       *ppUnoExc = 0;
410 
411       // reconvert temporary params
412       for ( ; nTempIndizes--; )
413       {
414         sal_Int32 nIndex = pTempIndizes[nTempIndizes];
415         typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
416 
417         if (pParams[nIndex].bIn)
418         {
419           if (pParams[nIndex].bOut) // inout
420           {
421             uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
422             uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
423                 pThis->getBridge()->getCpp2Uno() );
424           }
425         }
426         else // pure out
427         {
428           uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
429               pThis->getBridge()->getCpp2Uno() );
430         }
431         // destroy temp cpp param => cpp: every param was constructed
432         uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
433 
434         TYPELIB_DANGER_RELEASE( pParamTypeDescr );
435       }
436       // return value
437       if (pCppReturn && pUnoReturn != pCppReturn)
438       {
439         uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
440             pThis->getBridge()->getCpp2Uno() );
441         uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
442       }
443     }
444     catch (...)
445     {
446       // fill uno exception
447       fillUnoException( CPPU_CURRENT_NAMESPACE::__cxa_get_globals()->caughtExceptions,
448           *ppUnoExc, pThis->getBridge()->getCpp2Uno() );
449 
450       // temporary params
451       for ( ; nTempIndizes--; )
452       {
453         sal_Int32 nIndex = pTempIndizes[nTempIndizes];
454         // destroy temp cpp param => cpp: every param was constructed
455         uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], cpp_release );
456         TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
457       }
458       // return type
459       if (pReturnTypeDescr)
460         TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
461     }
462   }
463 
464 }
465 
466 
467 namespace bridges { namespace cpp_uno { namespace shared {
468 
469 //==================================================================================================
470 void unoInterfaceProxyDispatch(
471     uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
472     void * pReturn, void * pArgs[], uno_Any ** ppException )
473 {
474   // is my surrogate
475   bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
476     = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy *> (pUnoI);
477   //typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
478 
479 #ifdef BRDEBUG
480   fprintf(stderr,"in dispatch\n");
481 #endif
482 
483   switch (pMemberDescr->eTypeClass)
484   {
485     case typelib_TypeClass_INTERFACE_ATTRIBUTE:
486       {
487 
488         VtableSlot aVtableSlot(
489             getVtableSlot(
490               reinterpret_cast<
491               typelib_InterfaceAttributeTypeDescription const * >(
492                 pMemberDescr)));
493 
494         if (pReturn)
495         {
496           // dependent dispatch
497           cpp_call(
498               pThis, aVtableSlot,
499               ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
500               0, 0, // no params
501               pReturn, pArgs, ppException );
502         }
503         else
504         {
505           // is SET
506           typelib_MethodParameter aParam;
507           aParam.pTypeRef =
508             ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
509           aParam.bIn        = sal_True;
510           aParam.bOut       = sal_False;
511 
512           typelib_TypeDescriptionReference * pReturnTypeRef = 0;
513           OUString aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") );
514           typelib_typedescriptionreference_new(
515               &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
516 
517           // dependent dispatch
518           aVtableSlot.index += 1; //get then set method
519           cpp_call(
520               pThis, aVtableSlot,
521               pReturnTypeRef,
522               1, &aParam,
523               pReturn, pArgs, ppException );
524 
525           typelib_typedescriptionreference_release( pReturnTypeRef );
526         }
527 
528         break;
529       }
530     case typelib_TypeClass_INTERFACE_METHOD:
531       {
532 
533         VtableSlot aVtableSlot(
534             getVtableSlot(
535               reinterpret_cast<
536               typelib_InterfaceMethodTypeDescription const * >(
537                 pMemberDescr)));
538         switch (aVtableSlot.index)
539         {
540           // standard calls
541           case 1: // acquire uno interface
542             (*pUnoI->acquire)( pUnoI );
543             *ppException = 0;
544             break;
545           case 2: // release uno interface
546             (*pUnoI->release)( pUnoI );
547             *ppException = 0;
548             break;
549           case 0: // queryInterface() opt
550             {
551               typelib_TypeDescription * pTD = 0;
552               TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() );
553               if (pTD)
554               {
555                 uno_Interface * pInterface = 0;
556                 (*pThis->pBridge->getUnoEnv()->getRegisteredInterface)(
557                                                                        pThis->pBridge->getUnoEnv(),
558                                                                        (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
559 
560                 if (pInterface)
561                 {
562                   ::uno_any_construct(
563                       reinterpret_cast< uno_Any * >( pReturn ),
564                       &pInterface, pTD, 0 );
565                   (*pInterface->release)( pInterface );
566                   TYPELIB_DANGER_RELEASE( pTD );
567                   *ppException = 0;
568                   break;
569                 }
570                 TYPELIB_DANGER_RELEASE( pTD );
571               }
572             } // else perform queryInterface()
573           default:
574             // dependent dispatch
575             cpp_call(
576                 pThis, aVtableSlot,
577                 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef,
578                 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams,
579                 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams,
580                 pReturn, pArgs, ppException );
581         }
582         break;
583       }
584     default:
585       {
586         ::com::sun::star::uno::RuntimeException aExc(
587             OUString( RTL_CONSTASCII_USTRINGPARAM("illegal member type description!") ),
588             ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
589 
590         Type const & rExcType = ::getCppuType( &aExc );
591         // binary identical null reference
592         ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
593       }
594   }
595 }
596 }}}
597 
598