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