xref: /AOO41X/main/bridges/source/cpp_uno/gcc3_macosx_intel/uno2cpp.cxx (revision ff0525f24f03981d56b7579b645949f111420994)
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 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_bridges.hxx"
26 
27 #include <stdio.h>
28 
29 // #include <malloc.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 using namespace ::rtl;
43 using namespace ::com::sun::star::uno;
44 
45 namespace
46 {
47 
48 //==================================================================================================
49 // The call instruction within the asm section of callVirtualMethod may throw
50 // exceptions.  So that the compiler handles this correctly, it is important
51 // that (a) callVirtualMethod might call dummy_can_throw_anything (although this
52 // never happens at runtime), which in turn can throw exceptions, and (b)
53 // callVirtualMethod is not inlined at its call site (so that any exceptions are
54 // caught which are thrown from the instruction calling callVirtualMethod):
55 void callVirtualMethod(
56     void * pAdjustedThisPtr,
57     sal_Int32 nVtableIndex,
58     void * pRegisterReturn,
59     typelib_TypeDescription * pReturnTypeDescr, bool bSimpleReturn,
60     sal_Int32 * pStackLongs,
61     sal_Int32 nStackLongs ) __attribute__((noinline));
62 
63 void callVirtualMethod(
64     void * pAdjustedThisPtr,
65     sal_Int32 nVtableIndex,
66     void * pRegisterReturn,
67     typelib_TypeDescription * pReturnTypeDescr, bool bSimpleReturn,
68     sal_Int32 * pStackLongs,
69     sal_Int32 nStackLongs )
70 {
71     // parameter list is mixed list of * and values
72     // reference parameters are pointers
73 
74     OSL_ENSURE( pStackLongs && pAdjustedThisPtr, "### null ptr!" );
75     OSL_ENSURE( (sizeof(void *) == 4) && (sizeof(sal_Int32) == 4), "### unexpected size of int!" );
76     OSL_ENSURE( nStackLongs && pStackLongs, "### no stack in callVirtualMethod !" );
77 
78     // never called
79     if (! pAdjustedThisPtr) CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything("xxx"); // address something
80 
81     volatile long edx = 0, eax = 0; // for register returns
82     void * stackptr;
83     asm volatile (
84         "mov   %%esp, %6\n\t"
85         "mov   %0, %%eax\n\t"
86         "mov   %%eax, %%edx\n\t"
87                 // stack padding to keep stack aligned:
88         "shl   $2, %%eax\n\t"
89         "neg   %%eax\n\t"
90         "add   %%esp, %%eax\n\t"
91         "and   $0xf, %%eax\n\t"
92         "sub   %%eax, %%esp\n\t"
93                 // copy:
94         "mov   %%edx, %%eax\n\t"
95         "dec   %%edx\n\t"
96         "shl   $2, %%edx\n\t"
97         "add   %1, %%edx\n"
98         "Lcopy:\n\t"
99         "pushl 0(%%edx)\n\t"
100         "sub   $4, %%edx\n\t"
101         "dec   %%eax\n\t"
102         "jne   Lcopy\n\t"
103         // do the actual call
104         "mov   %2, %%edx\n\t"
105         "mov   0(%%edx), %%edx\n\t"
106         "mov   %3, %%eax\n\t"
107         "shl   $2, %%eax\n\t"
108         "add   %%eax, %%edx\n\t"
109         "mov   0(%%edx), %%edx\n\t"
110         "call  *%%edx\n\t"
111         // save return registers
112         "mov   %%eax, %4\n\t"
113         "mov   %%edx, %5\n\t"
114         // cleanup stack
115         "mov   %6, %%esp\n\t"
116         :
117         : "m"(nStackLongs), "m"(pStackLongs), "m"(pAdjustedThisPtr),
118           "m"(nVtableIndex), "m"(eax), "m"(edx), "m"(stackptr)
119         : "eax", "edx" );
120     switch( pReturnTypeDescr->eTypeClass )
121     {
122     case typelib_TypeClass_VOID:
123         break;
124     case typelib_TypeClass_HYPER:
125     case typelib_TypeClass_UNSIGNED_HYPER:
126         ((long*)pRegisterReturn)[1] = edx;
127     case typelib_TypeClass_LONG:
128     case typelib_TypeClass_UNSIGNED_LONG:
129     case typelib_TypeClass_CHAR:
130     case typelib_TypeClass_ENUM:
131         ((long*)pRegisterReturn)[0] = eax;
132         break;
133     case typelib_TypeClass_SHORT:
134     case typelib_TypeClass_UNSIGNED_SHORT:
135         *(unsigned short*)pRegisterReturn = eax;
136         break;
137     case typelib_TypeClass_BOOLEAN:
138     case typelib_TypeClass_BYTE:
139         *(unsigned char*)pRegisterReturn = eax;
140         break;
141     case typelib_TypeClass_FLOAT:
142         asm ( "fstps %0" : : "m"(*(char *)pRegisterReturn) );
143         break;
144     case typelib_TypeClass_DOUBLE:
145         asm ( "fstpl %0\n\t" : : "m"(*(char *)pRegisterReturn) );
146         break;
147     default: {
148         sal_Int32 const nRetSize = pReturnTypeDescr->nSize;
149         if (bSimpleReturn && nRetSize <= 8 && nRetSize > 0) {
150             if (nRetSize > 4)
151                 static_cast<long *>(pRegisterReturn)[1] = edx;
152             static_cast<long *>(pRegisterReturn)[0] = eax;
153         }
154         break;
155     }
156     }
157 }
158 
159 //==================================================================================================
160 static void cpp_call(
161     bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
162     bridges::cpp_uno::shared::VtableSlot aVtableSlot,
163     typelib_TypeDescriptionReference * pReturnTypeRef,
164     sal_Int32 nParams, typelib_MethodParameter * pParams,
165     void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
166 {
167     // max space for: [complex ret ptr], values|ptr ...
168     char * pCppStack        =
169         (char *)alloca( sizeof(sal_Int32) + ((nParams+2) * sizeof(sal_Int64)) );
170     char * pCppStackStart   = pCppStack;
171 
172     // return
173     typelib_TypeDescription * pReturnTypeDescr = 0;
174     TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
175     OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" );
176 
177     void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
178     bool bSimpleReturn = true;
179 
180     if (pReturnTypeDescr)
181     {
182         bSimpleReturn = CPPU_CURRENT_NAMESPACE::isSimpleReturnType(
183             pReturnTypeDescr);
184         if (bSimpleReturn)
185         {
186             pCppReturn = pUnoReturn; // direct way for simple types
187         }
188         else
189         {
190             pCppReturn = (bridges::cpp_uno::shared::relatesToInterfaceType(
191                               pReturnTypeDescr )
192                           ? alloca( pReturnTypeDescr->nSize )
193                           : pUnoReturn); // direct way
194             // complex return via ptr
195             *(void **)pCppStack = pCppReturn;
196             pCppStack += sizeof(void *);
197         }
198     }
199     // push this
200     void * pAdjustedThisPtr = reinterpret_cast< void ** >(pThis->getCppI())
201         + aVtableSlot.offset;
202     *(void**)pCppStack = pAdjustedThisPtr;
203     pCppStack += sizeof( void* );
204 
205     // stack space
206     OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" );
207     // args
208     void ** pCppArgs  = (void **)alloca( 3 * sizeof(void *) * nParams );
209     // indizes of values this have to be converted (interface conversion cpp<=>uno)
210     sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams);
211     // type descriptions for reconversions
212     typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
213 
214     sal_Int32 nTempIndizes   = 0;
215 
216     for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
217     {
218         const typelib_MethodParameter & rParam = pParams[nPos];
219         typelib_TypeDescription * pParamTypeDescr = 0;
220         TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
221 
222         if (!rParam.bOut
223             && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
224         {
225             uno_copyAndConvertData( pCppArgs[nPos] = pCppStack, pUnoArgs[nPos], pParamTypeDescr,
226                                     pThis->getBridge()->getUno2Cpp() );
227 
228             switch (pParamTypeDescr->eTypeClass)
229             {
230             case typelib_TypeClass_HYPER:
231             case typelib_TypeClass_UNSIGNED_HYPER:
232             case typelib_TypeClass_DOUBLE:
233                 pCppStack += sizeof(sal_Int32); // extra long
234             default:
235                 break;
236             }
237             // no longer needed
238             TYPELIB_DANGER_RELEASE( pParamTypeDescr );
239         }
240         else // ptr to complex value | ref
241         {
242             if (! rParam.bIn) // is pure out
243             {
244                 // cpp out is constructed mem, uno out is not!
245                 uno_constructData(
246                     *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
247                     pParamTypeDescr );
248                 pTempIndizes[nTempIndizes] = nPos; // default constructed for cpp call
249                 // will be released at reconversion
250                 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
251             }
252             // is in/inout
253             else if (bridges::cpp_uno::shared::relatesToInterfaceType(
254                          pParamTypeDescr ))
255             {
256                 uno_copyAndConvertData(
257                     *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
258                     pUnoArgs[nPos], pParamTypeDescr,
259                     pThis->getBridge()->getUno2Cpp() );
260 
261                 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
262                 // will be released at reconversion
263                 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
264             }
265             else // direct way
266             {
267                 *(void **)pCppStack = pCppArgs[nPos] = pUnoArgs[nPos];
268                 // no longer needed
269                 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
270             }
271         }
272         pCppStack += sizeof(sal_Int32); // standard parameter length
273     }
274 
275     try
276     {
277         OSL_ENSURE( !( (pCppStack - pCppStackStart ) & 3), "UNALIGNED STACK !!! (Please DO panic)" );
278         callVirtualMethod(
279             pAdjustedThisPtr, aVtableSlot.index,
280             pCppReturn, pReturnTypeDescr, bSimpleReturn,
281             (sal_Int32 *)pCppStackStart, (pCppStack - pCppStackStart) / sizeof(sal_Int32) );
282         // NO exception occured...
283         *ppUnoExc = 0;
284 
285         // reconvert temporary params
286         for ( ; nTempIndizes--; )
287         {
288             sal_Int32 nIndex = pTempIndizes[nTempIndizes];
289             typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
290 
291             if (pParams[nIndex].bIn)
292             {
293                 if (pParams[nIndex].bOut) // inout
294                 {
295                     uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
296                     uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
297                                             pThis->getBridge()->getCpp2Uno() );
298                 }
299             }
300             else // pure out
301             {
302                 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
303                                         pThis->getBridge()->getCpp2Uno() );
304             }
305             // destroy temp cpp param => cpp: every param was constructed
306             uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
307 
308             TYPELIB_DANGER_RELEASE( pParamTypeDescr );
309         }
310         // return value
311         if (pCppReturn && pUnoReturn != pCppReturn)
312         {
313             uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
314                                     pThis->getBridge()->getCpp2Uno() );
315             uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
316         }
317     }
318     catch (...)
319     {
320 #if OSL_DEBUG_LEVEL > 1
321     fprintf( stderr, "caught C++ exception\n" );
322 #endif
323         // fill uno exception
324         fillUnoException( CPPU_CURRENT_NAMESPACE::__cxa_get_globals()->caughtExceptions, *ppUnoExc, pThis->getBridge()->getCpp2Uno() );
325 
326         // temporary params
327         for ( ; nTempIndizes--; )
328         {
329             sal_Int32 nIndex = pTempIndizes[nTempIndizes];
330             // destroy temp cpp param => cpp: every param was constructed
331             uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], cpp_release );
332             TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
333         }
334         // return type
335         if (pReturnTypeDescr)
336             TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
337     }
338 }
339 
340 }
341 
342 namespace CPPU_CURRENT_NAMESPACE {
343 bool isSimpleReturnType(typelib_TypeDescription * pTD, bool recursive)
344 {
345     if (bridges::cpp_uno::shared::isSimpleType( pTD ))
346         return true;
347     // Only structs of exactly 1, 2, 4, or 8 bytes are returned through
348     // registers, see <http://developer.apple.com/documentation/DeveloperTools/
349     // Conceptual/LowLevelABI/Articles/IA32.html>:
350     if (pTD->eTypeClass == typelib_TypeClass_STRUCT &&
351         (recursive || pTD->nSize <= 2 || pTD->nSize == 4 || pTD->nSize == 8))
352     {
353         typelib_CompoundTypeDescription *const pCompTD =
354             (typelib_CompoundTypeDescription *) pTD;
355         for ( sal_Int32 pos = pCompTD->nMembers; pos--; ) {
356             typelib_TypeDescription * pMemberTD = 0;
357             TYPELIB_DANGER_GET( &pMemberTD, pCompTD->ppTypeRefs[pos] );
358             bool const b = isSimpleReturnType(pMemberTD, true);
359             TYPELIB_DANGER_RELEASE( pMemberTD );
360             if (! b)
361                 return false;
362         }
363         return true;
364     }
365     return false;
366 }
367 }
368 
369 //==================================================================================================
370 
371 namespace bridges { namespace cpp_uno { namespace shared {
372 void unoInterfaceProxyDispatch(
373     uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
374     void * pReturn, void * pArgs[], uno_Any ** ppException )
375 {
376     // is my surrogate
377     bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
378         = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
379 
380     switch (pMemberDescr->eTypeClass)
381     {
382     case typelib_TypeClass_INTERFACE_ATTRIBUTE:
383     {
384         VtableSlot aVtableSlot(
385             getVtableSlot(
386                 reinterpret_cast<
387                     typelib_InterfaceAttributeTypeDescription const * >(
388                         pMemberDescr)));
389         if (pReturn)
390         {
391             // dependent dispatch
392             cpp_call(
393                 pThis, aVtableSlot,
394                 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
395                 0, 0, // no params
396                 pReturn, pArgs, ppException );
397         }
398         else
399         {
400             // is SET
401             typelib_MethodParameter aParam;
402             aParam.pTypeRef =
403                 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
404             aParam.bIn      = sal_True;
405             aParam.bOut     = sal_False;
406 
407             typelib_TypeDescriptionReference * pReturnTypeRef = 0;
408             OUString aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") );
409             typelib_typedescriptionreference_new(
410                 &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
411 
412             // dependent dispatch
413             aVtableSlot.index += 1; // get, then set method
414             cpp_call(
415                 pThis, aVtableSlot,
416                 pReturnTypeRef,
417                 1, &aParam,
418                 pReturn, pArgs, ppException );
419 
420             typelib_typedescriptionreference_release( pReturnTypeRef );
421         }
422 
423         break;
424     }
425     case typelib_TypeClass_INTERFACE_METHOD:
426     {
427         VtableSlot aVtableSlot(
428             getVtableSlot(
429                 reinterpret_cast<
430                     typelib_InterfaceMethodTypeDescription const * >(
431                         pMemberDescr)));
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->pBridge->getUnoEnv()->getRegisteredInterface)(
451                     pThis->pBridge->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