xref: /trunk/main/bridges/source/cpp_uno/gcc3_freebsd_intel/uno2cpp.cxx (revision cf6516809c57e1bb0a940545cca99cdad54d4ce2)
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 <typeinfo>
28 #include <exception>
29 #include <cstddef>
30 #include <cxxabi.h>
31 #include <stdlib.h>
32 
33 #include <com/sun/star/uno/genfunc.hxx>
34 #include "com/sun/star/uno/RuntimeException.hpp"
35 #include <uno/data.h>
36 
37 #include "bridges/cpp_uno/shared/bridge.hxx"
38 #include "bridges/cpp_uno/shared/types.hxx"
39 #include "bridges/cpp_uno/shared/unointerfaceproxy.hxx"
40 #include "bridges/cpp_uno/shared/vtables.hxx"
41 
42 #include "share.hxx"
43 
44 using namespace ::rtl;
45 using namespace ::com::sun::star::uno;
46 #ifdef __GLIBCXX__
47 using CPPU_CURRENT_NAMESPACE::__cxa_exception;
48 using CPPU_CURRENT_NAMESPACE::__cxa_get_globals;
49 #else
50 using __cxxabiv1::__cxa_exception;
51 using __cxxabiv1::__cxa_current_primary_exception;
52 using __cxxabiv1::__cxa_decrement_exception_refcount;
53 #endif
54 
55 namespace
56 {
57 
58 //==================================================================================================
59 // The call instruction within the asm section of callVirtualMethod may throw
60 // exceptions.  So that the compiler handles this correctly, it is important
61 // that (a) callVirtualMethod might call dummy_can_throw_anything (although this
62 // never happens at runtime), which in turn can throw exceptions, and (b)
63 // callVirtualMethod is not inlined at its call site (so that any exceptions are
64 // caught which are thrown from the instruction calling callVirtualMethod):
65 void callVirtualMethod(
66     void * pAdjustedThisPtr,
67     sal_Int32 nVtableIndex,
68     void * pRegisterReturn,
69     typelib_TypeClass eReturnType,
70     sal_Int32 * pStackLongs,
71     sal_Int32 nStackLongs ) __attribute__((noinline));
72 
callVirtualMethod(void * pAdjustedThisPtr,sal_Int32 nVtableIndex,void * pRegisterReturn,typelib_TypeClass eReturnType,sal_Int32 * pStackLongs,sal_Int32 nStackLongs)73 void callVirtualMethod(
74     void * pAdjustedThisPtr,
75     sal_Int32 nVtableIndex,
76     void * pRegisterReturn,
77     typelib_TypeClass eReturnType,
78     sal_Int32 * pStackLongs,
79     sal_Int32 nStackLongs )
80 {
81     // parameter list is mixed list of * and values
82     // reference parameters are pointers
83 
84     OSL_ENSURE( pStackLongs && pAdjustedThisPtr, "### null ptr!" );
85     OSL_ENSURE( (sizeof(void *) == 4) && (sizeof(sal_Int32) == 4), "### unexpected size of int!" );
86     OSL_ENSURE( nStackLongs && pStackLongs, "### no stack in callVirtualMethod !" );
87 
88     // never called
89     if (! pAdjustedThisPtr) CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything("xxx"); // address something
90 
91     volatile long edx = 0, eax = 0; // for register returns
92     void * stackptr;
93     asm volatile (
94         "mov   %%esp, %6\n\t"
95         // preserve potential 128bit stack alignment
96         "and   $0xfffffff0, %%esp\n\t"
97         "mov   %0, %%eax\n\t"
98         "lea   -4(,%%eax,4), %%eax\n\t"
99         "and   $0xf, %%eax\n\t"
100         "sub   $0xc, %%eax\n\t"
101         "add   %%eax, %%esp\n\t"
102         // copy values
103         "mov   %0, %%eax\n\t"
104         "mov   %%eax, %%edx\n\t"
105         "dec   %%edx\n\t"
106         "shl   $2, %%edx\n\t"
107         "add   %1, %%edx\n"
108         "Lcopy:\n\t"
109         "pushl 0(%%edx)\n\t"
110         "sub   $4, %%edx\n\t"
111         "dec   %%eax\n\t"
112         "jne   Lcopy\n\t"
113         // do the actual call
114         "mov   %2, %%edx\n\t"
115         "mov   0(%%edx), %%edx\n\t"
116         "mov   %3, %%eax\n\t"
117         "shl   $2, %%eax\n\t"
118         "add   %%eax, %%edx\n\t"
119         "mov   0(%%edx), %%edx\n\t"
120         "call  *%%edx\n\t"
121         // save return registers
122         "mov   %%eax, %4\n\t"
123         "mov   %%edx, %5\n\t"
124         // cleanup stack
125         "mov   %6, %%esp\n\t"
126         :
127         : "m"(nStackLongs), "m"(pStackLongs), "m"(pAdjustedThisPtr),
128           "m"(nVtableIndex), "m"(eax), "m"(edx), "m"(stackptr)
129         : "eax", "edx" );
130     switch( eReturnType )
131     {
132         case typelib_TypeClass_HYPER:
133         case typelib_TypeClass_UNSIGNED_HYPER:
134             ((long*)pRegisterReturn)[1] = edx;
135         case typelib_TypeClass_LONG:
136         case typelib_TypeClass_UNSIGNED_LONG:
137         case typelib_TypeClass_CHAR:
138         case typelib_TypeClass_ENUM:
139             ((long*)pRegisterReturn)[0] = eax;
140             break;
141         case typelib_TypeClass_SHORT:
142         case typelib_TypeClass_UNSIGNED_SHORT:
143             *(unsigned short*)pRegisterReturn = eax;
144             break;
145         case typelib_TypeClass_BOOLEAN:
146         case typelib_TypeClass_BYTE:
147             *(unsigned char*)pRegisterReturn = eax;
148             break;
149         case typelib_TypeClass_FLOAT:
150             asm ( "fstps %0" : : "m"(*(char *)pRegisterReturn) );
151             break;
152         case typelib_TypeClass_DOUBLE:
153             asm ( "fstpl %0\n\t" : : "m"(*(char *)pRegisterReturn) );
154             break;
155         default:
156             break;
157     }
158 }
159 
160 //==================================================================================================
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)161 static void cpp_call(
162     bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
163     bridges::cpp_uno::shared::VtableSlot aVtableSlot,
164     typelib_TypeDescriptionReference * pReturnTypeRef,
165     sal_Int32 nParams, typelib_MethodParameter * pParams,
166     void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
167 {
168     // max space for: [complex ret ptr], values|ptr ...
169     char * pCppStack        =
170         (char *)alloca( sizeof(sal_Int32) + ((nParams+2) * sizeof(sal_Int64)) );
171     char * pCppStackStart   = pCppStack;
172 
173     // return
174     typelib_TypeDescription * pReturnTypeDescr = 0;
175     TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
176     OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" );
177 
178     void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
179 
180     if (pReturnTypeDescr)
181     {
182         if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr ))
183         {
184             pCppReturn = pUnoReturn; // direct way for simple types
185         }
186         else
187         {
188             // complex return via ptr
189             pCppReturn = *(void **)pCppStack
190                 = (bridges::cpp_uno::shared::relatesToInterfaceType(
191                        pReturnTypeDescr )
192                    ? alloca( pReturnTypeDescr->nSize )
193                    : pUnoReturn); // direct way
194             pCppStack += sizeof(void *);
195         }
196     }
197     // push this
198     void * pAdjustedThisPtr = reinterpret_cast< void ** >(pThis->getCppI())
199         + aVtableSlot.offset;
200     *(void**)pCppStack = pAdjustedThisPtr;
201     pCppStack += sizeof( void* );
202 
203     // stack space
204     OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" );
205     // args
206     void ** pCppArgs  = (void **)alloca( 3 * sizeof(void *) * nParams );
207     // indizes of values this have to be converted (interface conversion cpp<=>uno)
208     sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams);
209     // type descriptions for reconversions
210     typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
211 
212     sal_Int32 nTempIndizes   = 0;
213 
214     for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
215     {
216         const typelib_MethodParameter & rParam = pParams[nPos];
217         typelib_TypeDescription * pParamTypeDescr = 0;
218         TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
219 
220         if (!rParam.bOut
221             && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
222         {
223             uno_copyAndConvertData( pCppArgs[nPos] = pCppStack, pUnoArgs[nPos], pParamTypeDescr,
224                                     pThis->getBridge()->getUno2Cpp() );
225 
226             switch (pParamTypeDescr->eTypeClass)
227             {
228             case typelib_TypeClass_HYPER:
229             case typelib_TypeClass_UNSIGNED_HYPER:
230             case typelib_TypeClass_DOUBLE:
231                 pCppStack += sizeof(sal_Int32); // extra long
232                 break;
233             default:
234                 break;
235             }
236             // no longer needed
237             TYPELIB_DANGER_RELEASE( pParamTypeDescr );
238         }
239         else // ptr to complex value | ref
240         {
241             if (! rParam.bIn) // is pure out
242             {
243                 // cpp out is constructed mem, uno out is not!
244                 uno_constructData(
245                     *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
246                     pParamTypeDescr );
247                 pTempIndizes[nTempIndizes] = nPos; // default constructed for cpp call
248                 // will be released at reconversion
249                 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
250             }
251             // is in/inout
252             else if (bridges::cpp_uno::shared::relatesToInterfaceType(
253                          pParamTypeDescr ))
254             {
255                 uno_copyAndConvertData(
256                     *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
257                     pUnoArgs[nPos], pParamTypeDescr,
258                     pThis->getBridge()->getUno2Cpp() );
259 
260                 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
261                 // will be released at reconversion
262                 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
263             }
264             else // direct way
265             {
266                 *(void **)pCppStack = pCppArgs[nPos] = pUnoArgs[nPos];
267                 // no longer needed
268                 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
269             }
270         }
271         pCppStack += sizeof(sal_Int32); // standard parameter length
272     }
273 
274     try
275     {
276         OSL_ENSURE( !( (pCppStack - pCppStackStart ) & 3), "UNALIGNED STACK !!! (Please DO panic)" );
277         callVirtualMethod(
278             pAdjustedThisPtr, aVtableSlot.index,
279             pCppReturn, pReturnTypeDescr->eTypeClass,
280             (sal_Int32 *)pCppStackStart, (pCppStack - pCppStackStart) / sizeof(sal_Int32) );
281         // NO exception occurred...
282         *ppUnoExc = 0;
283 
284         // reconvert temporary params
285         for ( ; nTempIndizes--; )
286         {
287             sal_Int32 nIndex = pTempIndizes[nTempIndizes];
288             typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
289 
290             if (pParams[nIndex].bIn)
291             {
292                 if (pParams[nIndex].bOut) // inout
293                 {
294                     uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
295                     uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
296                                             pThis->getBridge()->getCpp2Uno() );
297                 }
298             }
299             else // pure out
300             {
301                 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
302                                         pThis->getBridge()->getCpp2Uno() );
303             }
304             // destroy temp cpp param => cpp: every param was constructed
305             uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
306 
307             TYPELIB_DANGER_RELEASE( pParamTypeDescr );
308         }
309         // return value
310         if (pCppReturn && pUnoReturn != pCppReturn)
311         {
312             uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
313                                     pThis->getBridge()->getCpp2Uno() );
314             uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
315         }
316     }
317     catch (...)
318     {
319         __cxa_exception *header;
320 #ifdef __GLIBCXX__
321         header = __cxa_get_globals()->caughtExceptions;
322 #else
323         header = reinterpret_cast<__cxa_exception *>( __cxa_current_primary_exception() );
324         if (header) {
325             __cxa_decrement_exception_refcount( header );
326             header--;
327             uint64_t exc_class = header->unwindHeader.exception_class
328                        & 0xffffffffffffff00;
329             if (exc_class != /* "GNUCC++" */ 0x474e5543432b2b00) {
330                 // _Unwind_Exception was made __aligned__ which
331                 // increased its size by 12 bytes.
332                 header = reinterpret_cast<__cxa_exception *>(
333                     reinterpret_cast<char *>( header ) - 12 );
334                 exc_class = header->unwindHeader.exception_class
335                       & 0xffffffffffffff00;
336                 if (exc_class != /* "GNUCC++" */ 0x474e5543432b2b00) {
337                     header = nullptr;
338                 }
339             }
340         }
341 #endif
342         // fill uno exception
343         CPPU_CURRENT_NAMESPACE::fillUnoException( header, *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         // return type
354         if (pReturnTypeDescr)
355             TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
356     }
357 }
358 
359 }
360 
361 namespace bridges { namespace cpp_uno { namespace shared {
362 
unoInterfaceProxyDispatch(uno_Interface * pUnoI,const typelib_TypeDescription * pMemberDescr,void * pReturn,void * pArgs[],uno_Any ** ppException)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 
371     switch (pMemberDescr->eTypeClass)
372     {
373     case typelib_TypeClass_INTERFACE_ATTRIBUTE:
374     {
375         VtableSlot aVtableSlot(
376             getVtableSlot(
377                 reinterpret_cast<
378                     typelib_InterfaceAttributeTypeDescription const * >(
379                         pMemberDescr)));
380         if (pReturn)
381         {
382             // dependent dispatch
383             cpp_call(
384                 pThis, aVtableSlot,
385                 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
386                 0, 0, // no params
387                 pReturn, pArgs, ppException );
388         }
389         else
390         {
391             // is SET
392             typelib_MethodParameter aParam;
393             aParam.pTypeRef =
394                 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
395             aParam.bIn      = sal_True;
396             aParam.bOut     = sal_False;
397 
398             typelib_TypeDescriptionReference * pReturnTypeRef = 0;
399             OUString aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") );
400             typelib_typedescriptionreference_new(
401                 &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
402 
403             // dependent dispatch
404             aVtableSlot.index += 1; // get, then set method
405             cpp_call(
406                 pThis, aVtableSlot,
407                 pReturnTypeRef,
408                 1, &aParam,
409                 pReturn, pArgs, ppException );
410 
411             typelib_typedescriptionreference_release( pReturnTypeRef );
412         }
413 
414         break;
415     }
416     case typelib_TypeClass_INTERFACE_METHOD:
417     {
418         VtableSlot aVtableSlot(
419             getVtableSlot(
420                 reinterpret_cast<
421                     typelib_InterfaceMethodTypeDescription const * >(
422                         pMemberDescr)));
423         switch (aVtableSlot.index)
424         {
425             // standard calls
426         case 1: // acquire uno interface
427             (*pUnoI->acquire)( pUnoI );
428             *ppException = 0;
429             break;
430         case 2: // release uno interface
431             (*pUnoI->release)( pUnoI );
432             *ppException = 0;
433             break;
434         case 0: // queryInterface() opt
435         {
436             typelib_TypeDescription * pTD = 0;
437             TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() );
438             if (pTD)
439             {
440                 uno_Interface * pInterface = 0;
441                 (*pThis->pBridge->getUnoEnv()->getRegisteredInterface)(
442                     pThis->pBridge->getUnoEnv(),
443                     (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
444 
445                 if (pInterface)
446                 {
447                     ::uno_any_construct(
448                         reinterpret_cast< uno_Any * >( pReturn ),
449                         &pInterface, pTD, 0 );
450                     (*pInterface->release)( pInterface );
451                     TYPELIB_DANGER_RELEASE( pTD );
452                     *ppException = 0;
453                     break;
454                 }
455                 TYPELIB_DANGER_RELEASE( pTD );
456             }
457         } // else perform queryInterface()
458         default:
459             // dependent dispatch
460             cpp_call(
461                 pThis, aVtableSlot,
462                 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef,
463                 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams,
464                 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams,
465                 pReturn, pArgs, ppException );
466         }
467         break;
468     }
469     default:
470     {
471         ::com::sun::star::uno::RuntimeException aExc(
472             OUString( RTL_CONSTASCII_USTRINGPARAM("illegal member type description!") ),
473             ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
474 
475         Type const & rExcType = ::getCppuType( &aExc );
476         // binary identical null reference
477         ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
478     }
479     }
480 }
481 
482 } } }
483