xref: /trunk/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/uno2cpp.cxx (revision adce10bba5577426ee4829485de8508d0c6fd41c)
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 <exception>
28 #include <typeinfo>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 
33 #include "rtl/alloc.h"
34 #include "rtl/ustrbuf.hxx"
35 
36 #include <com/sun/star/uno/genfunc.hxx>
37 #include "com/sun/star/uno/RuntimeException.hpp"
38 #include <uno/data.h>
39 
40 #include <bridges/cpp_uno/shared/bridge.hxx>
41 #include <bridges/cpp_uno/shared/types.hxx>
42 #include "bridges/cpp_uno/shared/unointerfaceproxy.hxx"
43 #include "bridges/cpp_uno/shared/vtables.hxx"
44 
45 #include "abi.hxx"
46 #include "share.hxx"
47 
48 using namespace ::rtl;
49 using namespace ::com::sun::star::uno;
50 
51 //==================================================================================================
52 
53 // The AArch64 outgoing-call trampoline, implemented in call.s.  It loads the
54 // argument registers from the caller-prepared arrays, copies overflow args to
55 // the outgoing stack, performs the indirect call, and returns x0/x1 and d0..d3.
56 extern "C" void callVirtualFunction(
57     sal_uInt64 pFunction, sal_uInt64 pIndirectRet,
58     sal_uInt64 *pGPR, double *pFPR,
59     unsigned char *pStack, sal_uInt32 nStackBytes,
60     sal_uInt64 *pGPRReturn, double *pFPRReturn );
61 
62 static void callVirtualMethod(void * pThis, sal_uInt32 nVtableIndex,
63                               void * pRegisterReturn, typelib_TypeDescriptionReference * pReturnTypeRef, bool bSimpleReturn,
64                               void * pIndirectReturn,
65                               unsigned char *pStack, sal_uInt32 nStack,
66                               sal_uInt64 *pGPR, sal_uInt32 nGPR,
67                               double *pFPR, sal_uInt32 nFPR) __attribute__((noinline));
68 
callVirtualMethod(void * pThis,sal_uInt32 nVtableIndex,void * pRegisterReturn,typelib_TypeDescriptionReference * pReturnTypeRef,bool bSimpleReturn,void * pIndirectReturn,unsigned char * pStack,sal_uInt32 nStack,sal_uInt64 * pGPR,sal_uInt32 nGPR,double * pFPR,sal_uInt32 nFPR)69 static void callVirtualMethod(void * pThis, sal_uInt32 nVtableIndex,
70                               void * pRegisterReturn, typelib_TypeDescriptionReference * pReturnTypeRef, bool bSimpleReturn,
71                               void * pIndirectReturn,
72                                unsigned char *pStack, sal_uInt32 nStack,
73                               sal_uInt64 *pGPR, sal_uInt32 nGPR,
74                               double *pFPR, sal_uInt32 nFPR)
75 {
76 #if OSL_DEBUG_LEVEL > 1
77     // Let's figure out what is really going on here
78     {
79         fprintf( stderr, "= callVirtualMethod() =\nGPR's (%d): ", nGPR );
80         for ( unsigned int i = 0; i < nGPR; ++i )
81             fprintf( stderr, "0x%lx, ", pGPR[i] );
82         fprintf( stderr, "\nFPR's (%d): ", nFPR );
83         for ( unsigned int i = 0; i < nFPR; ++i )
84             fprintf( stderr, "%f, ", pFPR[i] );
85         // The overflow area is a packed byte image, not an array of words.
86         fprintf( stderr, "\nStack (%d bytes): ", nStack );
87         for ( unsigned int i = 0; i < nStack; ++i )
88             fprintf( stderr, "%02x ", pStack[i] );
89         fprintf( stderr, "\n" );
90     }
91 #endif
92 
93     // The call instruction within callVirtualFunction may throw exceptions.  So
94     // that the compiler handles this correctly, it is important that (a)
95     // callVirtualMethod might call dummy_can_throw_anything (although this never
96     // happens at runtime), which in turn can throw exceptions, and (b)
97     // callVirtualMethod is not inlined at its call site (so that any exceptions
98     // thrown across the call are caught):
99     if ( !pThis )
100         CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything( "xxx" ); // address something
101 
102     // Should not happen, but...
103     if ( nFPR > aarch64::MAX_FPR_REGS )
104         nFPR = aarch64::MAX_FPR_REGS;
105     if ( nGPR > aarch64::MAX_GPR_REGS )
106         nGPR = aarch64::MAX_GPR_REGS;
107 
108     // Get pointer to the C++ virtual method from the vtable.
109     sal_uInt64 pMethod = *((sal_uInt64 *)pThis);
110     pMethod += 8 * nVtableIndex;
111     pMethod = *((sal_uInt64 *)pMethod);
112 
113     // Return register save areas: x0,x1 and d0..d3 (HFA up to 4 elements).
114     sal_uInt64 gpReturn[2] = { 0, 0 };
115     double fpReturn[4] = { 0, 0, 0, 0 };
116 
117     // Ensure the GPR/FPR arrays are the full register width even if fewer were
118     // filled (the trampoline always loads all 8 of each).
119     sal_uInt64 gpr[aarch64::MAX_GPR_REGS];
120     double fpr[aarch64::MAX_FPR_REGS];
121     for ( sal_uInt32 i = 0; i < aarch64::MAX_GPR_REGS; ++i )
122         gpr[i] = ( i < nGPR ) ? pGPR[i] : 0;
123     for ( sal_uInt32 i = 0; i < aarch64::MAX_FPR_REGS; ++i )
124         fpr[i] = ( i < nFPR ) ? pFPR[i] : 0;
125 
126     callVirtualFunction(
127         pMethod,
128         reinterpret_cast<sal_uInt64>( pIndirectReturn ), // x8, 0 if none
129         gpr, fpr,
130         pStack, nStack,
131         gpReturn, fpReturn );
132 
133     switch (pReturnTypeRef->eTypeClass)
134     {
135     case typelib_TypeClass_HYPER:
136     case typelib_TypeClass_UNSIGNED_HYPER:
137         *reinterpret_cast<sal_uInt64 *>( pRegisterReturn ) = gpReturn[0];
138         break;
139     case typelib_TypeClass_LONG:
140         *reinterpret_cast<sal_Int32 *>( pRegisterReturn ) =
141             *reinterpret_cast<sal_Int32 *>( &gpReturn[0] );
142         break;
143     case typelib_TypeClass_UNSIGNED_LONG:
144     case typelib_TypeClass_ENUM:
145         *reinterpret_cast<sal_uInt32 *>( pRegisterReturn ) =
146             *reinterpret_cast<sal_uInt32 *>( &gpReturn[0] );
147         break;
148     case typelib_TypeClass_CHAR:
149     case typelib_TypeClass_UNSIGNED_SHORT:
150         *reinterpret_cast<sal_uInt16 *>( pRegisterReturn ) = *reinterpret_cast<sal_uInt16*>( &gpReturn[0] );
151         break;
152     case typelib_TypeClass_SHORT:
153         *reinterpret_cast<sal_Int16 *>( pRegisterReturn ) =
154             *reinterpret_cast<sal_Int16 *>( &gpReturn[0] );
155         break;
156     case typelib_TypeClass_BOOLEAN:
157         *reinterpret_cast<sal_uInt8 *>( pRegisterReturn ) = *reinterpret_cast<sal_uInt8*>( &gpReturn[0] );
158         break;
159     case typelib_TypeClass_BYTE:
160         *reinterpret_cast<sal_Int8 *>( pRegisterReturn ) =
161             *reinterpret_cast<sal_Int8 *>( &gpReturn[0] );
162         break;
163     case typelib_TypeClass_FLOAT:
164         *reinterpret_cast<float *>( pRegisterReturn ) =
165             *reinterpret_cast<float *>( &fpReturn[0] );
166         break;
167     case typelib_TypeClass_DOUBLE:
168         *reinterpret_cast<double *>( pRegisterReturn ) = fpReturn[0];
169         break;
170     default:
171         {
172             sal_Int32 const nRetSize = pReturnTypeRef->pType->nSize;
173             if (bSimpleReturn && nRetSize > 0)
174             {
175                 // Register-returned aggregate: an HFA arrives in d0..d3, a
176                 // non-HFA <= 16 bytes in x0,x1.  fill_struct picks the right one.
177                 aarch64::fill_struct( pReturnTypeRef, &gpReturn[0], &fpReturn[0], pRegisterReturn);
178             }
179             break;
180         }
181     }
182 }
183 
184 //==================================================================================================
185 
186 // Macros for inserting values into registers. Stack arguments are handled
187 // separately with a byte cursor because Apple packs them by size/alignment.
188 // pSV - pointer to the source
189 // nr - order of the value [will be increased if stored to register]
190 // pFPR, pGPR - pointer to the registers
191 
192 // Each pFPR slot is the low 64 bits of a v register.  A float occupies only
193 // the low 32 bits, while a double occupies all 64 bits.
194 #define INSERT_FLOAT( pSV, nr, pFPR ) \
195     if ( nr < aarch64::MAX_FPR_REGS ) \
196     { \
197         pFPR[nr] = 0; \
198         *reinterpret_cast<float *>( pFPR + nr++ ) = *reinterpret_cast<const float *>( pSV ); \
199     }
200 
201 #define INSERT_DOUBLE( pSV, nr, pFPR ) \
202     if ( nr < aarch64::MAX_FPR_REGS ) \
203         pFPR[nr++] = *reinterpret_cast<const double *>( pSV );
204 
205 #define INSERT_INT64( pSV, nr, pGPR ) \
206     if ( nr < aarch64::MAX_GPR_REGS ) \
207         pGPR[nr++] = *reinterpret_cast<const sal_uInt64 *>( pSV );
208 
209 #define INSERT_INT32( pSV, nr, pGPR ) \
210     if ( nr < aarch64::MAX_GPR_REGS ) \
211         pGPR[nr++] = *reinterpret_cast<const sal_uInt32 *>( pSV );
212 
213 #define INSERT_SIGNED_INT32( pSV, nr, pGPR ) \
214     if ( nr < aarch64::MAX_GPR_REGS ) \
215         pGPR[nr++] = static_cast<sal_Int64>( *reinterpret_cast<const sal_Int32 *>( pSV ) );
216 
217 #define INSERT_INT16( pSV, nr, pGPR ) \
218     if ( nr < aarch64::MAX_GPR_REGS ) \
219         pGPR[nr++] = *reinterpret_cast<const sal_uInt16 *>( pSV );
220 
221 #define INSERT_SIGNED_INT16( pSV, nr, pGPR ) \
222     if ( nr < aarch64::MAX_GPR_REGS ) \
223         pGPR[nr++] = static_cast<sal_Int64>( *reinterpret_cast<const sal_Int16 *>( pSV ) );
224 
225 #define INSERT_INT8( pSV, nr, pGPR ) \
226     if ( nr < aarch64::MAX_GPR_REGS ) \
227         pGPR[nr++] = *reinterpret_cast<const sal_uInt8 *>( pSV );
228 
229 #define INSERT_SIGNED_INT8( pSV, nr, pGPR ) \
230     if ( nr < aarch64::MAX_GPR_REGS ) \
231         pGPR[nr++] = static_cast<sal_Int64>( *reinterpret_cast<const sal_Int8 *>( pSV ) );
232 
233 //==================================================================================================
234 
235 namespace {
236 
appendCString(OUStringBuffer & buffer,char const * text)237 void appendCString(OUStringBuffer & buffer, char const * text) {
238     if (text != 0) {
239         buffer.append(
240             OStringToOUString(OString(text), RTL_TEXTENCODING_ISO_8859_1));
241             // use 8859-1 to avoid conversion failure
242     }
243 }
244 
245 }
246 
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)247 static void cpp_call(
248     bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
249     bridges::cpp_uno::shared::VtableSlot aVtableSlot,
250     typelib_TypeDescriptionReference * pReturnTypeRef,
251     sal_Int32 nParams, typelib_MethodParameter * pParams,
252     void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
253 {
254     unsigned char *pStackStart = static_cast<unsigned char *>(
255         __builtin_alloca( (nParams + 3) * sizeof(sal_uInt64) ) );
256     sal_uInt32 nStack = 0;
257 
258     sal_uInt64 pGPR[aarch64::MAX_GPR_REGS];
259     sal_uInt32 nGPR = 0;
260 
261     double pFPR[aarch64::MAX_FPR_REGS];
262     sal_uInt32 nFPR = 0;
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 (see below)
270 
271     // Indirect-result pointer. On AArch64 this is passed in the dedicated x8
272     // register, NOT as the first general-purpose argument (unlike x86-64 SysV).
273     // So we do NOT insert it into pGPR here; it is threaded to the trampoline
274     // separately as pIndirectReturn.
275     void * pIndirectReturn = 0;
276 
277     bool bSimpleReturn = true;
278     if ( pReturnTypeDescr )
279     {
280         if ( aarch64::return_in_hidden_param( pReturnTypeRef ) )
281             bSimpleReturn = false;
282 
283         if ( bSimpleReturn )
284             pCppReturn = pUnoReturn; // direct way for simple types
285         else
286         {
287             // complex return via the x8 indirect-result buffer
288             pCppReturn = bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )?
289                          __builtin_alloca( pReturnTypeDescr->nSize ) : pUnoReturn;
290             pIndirectReturn = pCppReturn;
291         }
292     }
293 
294     // Push "this" pointer
295     void * pAdjustedThisPtr = reinterpret_cast< void ** >( pThis->getCppI() ) + aVtableSlot.offset;
296     INSERT_INT64( &pAdjustedThisPtr, nGPR, pGPR );
297 
298     // Args
299     void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams );
300     // Indizes of values this have to be converted (interface conversion cpp<=>uno)
301     sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams);
302     // Type descriptions for reconversions
303     typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
304 
305     sal_Int32 nTempIndizes = 0;
306 
307     for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
308     {
309         const typelib_MethodParameter & rParam = pParams[nPos];
310         typelib_TypeDescription * pParamTypeDescr = 0;
311         TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
312 
313         if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
314         {
315             uno_copyAndConvertData( pCppArgs[nPos] = alloca( 8 ), pUnoArgs[nPos], pParamTypeDescr,
316                                     pThis->getBridge()->getUno2Cpp() );
317             bool onStack = false;
318 
319             switch (pParamTypeDescr->eTypeClass)
320             {
321             case typelib_TypeClass_HYPER:
322             case typelib_TypeClass_UNSIGNED_HYPER:
323                 onStack = nGPR >= aarch64::MAX_GPR_REGS;
324                 INSERT_INT64( pCppArgs[nPos], nGPR, pGPR );
325                 break;
326             case typelib_TypeClass_LONG:
327                 onStack = nGPR >= aarch64::MAX_GPR_REGS;
328                 INSERT_SIGNED_INT32( pCppArgs[nPos], nGPR, pGPR );
329                 break;
330             case typelib_TypeClass_UNSIGNED_LONG:
331             case typelib_TypeClass_ENUM:
332                 onStack = nGPR >= aarch64::MAX_GPR_REGS;
333                 INSERT_INT32( pCppArgs[nPos], nGPR, pGPR );
334                 break;
335             case typelib_TypeClass_SHORT:
336                 onStack = nGPR >= aarch64::MAX_GPR_REGS;
337                 INSERT_SIGNED_INT16( pCppArgs[nPos], nGPR, pGPR );
338                 break;
339             case typelib_TypeClass_CHAR:
340             case typelib_TypeClass_UNSIGNED_SHORT:
341                 onStack = nGPR >= aarch64::MAX_GPR_REGS;
342                 INSERT_INT16( pCppArgs[nPos], nGPR, pGPR );
343                 break;
344             case typelib_TypeClass_BYTE:
345                 onStack = nGPR >= aarch64::MAX_GPR_REGS;
346                 INSERT_SIGNED_INT8( pCppArgs[nPos], nGPR, pGPR );
347                 break;
348             case typelib_TypeClass_BOOLEAN:
349                 onStack = nGPR >= aarch64::MAX_GPR_REGS;
350                 INSERT_INT8( pCppArgs[nPos], nGPR, pGPR );
351                 break;
352             case typelib_TypeClass_FLOAT:
353                 onStack = nFPR >= aarch64::MAX_FPR_REGS;
354                 INSERT_FLOAT( pCppArgs[nPos], nFPR, pFPR );
355                 break;
356             case typelib_TypeClass_DOUBLE:
357                 onStack = nFPR >= aarch64::MAX_FPR_REGS;
358                 INSERT_DOUBLE( pCppArgs[nPos], nFPR, pFPR );
359                 break;
360             default:
361                 break;
362             }
363             if ( onStack )
364             {
365                 nStack = aarch64::align_stack_offset( nStack, rParam.pTypeRef );
366                 sal_uInt32 size = aarch64::stack_size( rParam.pTypeRef );
367                 memcpy( pStackStart + nStack, pCppArgs[nPos], size );
368                 nStack += size;
369             }
370 
371             // no longer needed
372             TYPELIB_DANGER_RELEASE( pParamTypeDescr );
373         }
374         else // ptr to complex value | ref
375         {
376             if (! rParam.bIn) // is pure out
377             {
378                 // cpp out is constructed mem, uno out is not!
379                 uno_constructData(
380                     pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
381                     pParamTypeDescr );
382                 pTempIndizes[nTempIndizes] = nPos; // default constructed for cpp call
383                 // will be released at reconversion
384                 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
385             }
386             // is in/inout
387             else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
388             {
389                 uno_copyAndConvertData(
390                     pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
391                     pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
392 
393                 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
394                 // will be released at reconversion
395                 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
396             }
397             else // direct way
398             {
399                 pCppArgs[nPos] = pUnoArgs[nPos];
400                 // no longer needed
401                 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
402             }
403             if ( nGPR < aarch64::MAX_GPR_REGS )
404             {
405                 INSERT_INT64( &(pCppArgs[nPos]), nGPR, pGPR );
406             }
407             else
408             {
409                 nStack = (nStack + sizeof(void *) - 1) & ~(sizeof(void *) - 1);
410                 memcpy( pStackStart + nStack, &pCppArgs[nPos], sizeof(void *) );
411                 nStack += sizeof(void *);
412             }
413         }
414     }
415 
416     try
417     {
418         try {
419             callVirtualMethod(
420                 pAdjustedThisPtr, aVtableSlot.index,
421                 pCppReturn, pReturnTypeRef, bSimpleReturn,
422                 pIndirectReturn,
423                 pStackStart, nStack,
424                 pGPR, nGPR,
425                 pFPR, nFPR );
426         } catch (Exception &) {
427             throw;
428         } catch (std::exception & e) {
429             OUStringBuffer buf;
430             buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("C++ code threw "));
431             appendCString(buf, typeid(e).name());
432             buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(": "));
433             appendCString(buf, e.what());
434             throw RuntimeException(
435                 buf.makeStringAndClear(), Reference< XInterface >());
436         } catch (...) {
437             throw RuntimeException(
438                 OUString(
439                     RTL_CONSTASCII_USTRINGPARAM(
440                         "C++ code threw unknown exception")),
441                 Reference< XInterface >());
442         }
443 
444         // NO exception occurred...
445         *ppUnoExc = 0;
446 
447         // reconvert temporary params
448         for ( ; nTempIndizes--; )
449         {
450             sal_Int32 nIndex = pTempIndizes[nTempIndizes];
451             typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
452 
453             if (pParams[nIndex].bIn)
454             {
455                 if (pParams[nIndex].bOut) // inout
456                 {
457                     uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
458                     uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
459                                             pThis->getBridge()->getCpp2Uno() );
460                 }
461             }
462             else // pure out
463             {
464                 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
465                                         pThis->getBridge()->getCpp2Uno() );
466             }
467             // destroy temp cpp param => cpp: every param was constructed
468             uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
469 
470             TYPELIB_DANGER_RELEASE( pParamTypeDescr );
471         }
472         // return value
473         if (pCppReturn && pUnoReturn != pCppReturn)
474         {
475             uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
476                                     pThis->getBridge()->getCpp2Uno() );
477             uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
478         }
479     }
480     catch (Exception & e)
481     {
482         // fill uno exception
483         std::type_info * type = CPPU_CURRENT_NAMESPACE::__cxa_current_exception_type();
484         CPPU_CURRENT_NAMESPACE::fillUnoException(
485             type ? *type : typeid(e), &e, *ppUnoExc,
486             pThis->getBridge()->getCpp2Uno() );
487 
488         // temporary params
489         for ( ; nTempIndizes--; )
490         {
491             sal_Int32 nIndex = pTempIndizes[nTempIndizes];
492             // destroy temp cpp param => cpp: every param was constructed
493             uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], cpp_release );
494             TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
495         }
496         // return type
497         if (pReturnTypeDescr)
498             TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
499     }
500     catch (...)
501     {
502         RuntimeException e(
503             OUString( RTL_CONSTASCII_USTRINGPARAM("C++ code threw unknown exception") ),
504             Reference< XInterface >() );
505         uno_type_any_constructAndConvert(
506             *ppUnoExc, &e, ::getCppuType( &e ).getTypeLibType(),
507             pThis->getBridge()->getCpp2Uno() );
508         for ( ; nTempIndizes--; )
509         {
510             sal_Int32 nIndex = pTempIndizes[nTempIndizes];
511             uno_destructData(
512                 pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], cpp_release );
513             TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
514         }
515         if (pReturnTypeDescr)
516             TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
517     }
518 }
519 
520 //==================================================================================================
521 
522 namespace bridges { namespace cpp_uno { namespace shared {
523 
unoInterfaceProxyDispatch(uno_Interface * pUnoI,const typelib_TypeDescription * pMemberDescr,void * pReturn,void * pArgs[],uno_Any ** ppException)524 void unoInterfaceProxyDispatch(
525     uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
526     void * pReturn, void * pArgs[], uno_Any ** ppException )
527 {
528     // is my surrogate
529     bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
530         = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
531 #if OSL_DEBUG_LEVEL > 0
532     typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
533 #endif
534 
535     switch (pMemberDescr->eTypeClass)
536     {
537     case typelib_TypeClass_INTERFACE_ATTRIBUTE:
538     {
539 #if OSL_DEBUG_LEVEL > 0
540         // determine vtable call index
541         sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition;
542         OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### member pos out of range!" );
543 #endif
544         VtableSlot aVtableSlot(
545                 getVtableSlot(
546                     reinterpret_cast<
547                     typelib_InterfaceAttributeTypeDescription const * >(
548                         pMemberDescr)));
549 
550         if (pReturn)
551         {
552             // dependent dispatch
553             cpp_call(
554                 pThis, aVtableSlot,
555                 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
556                 0, 0, // no params
557                 pReturn, pArgs, ppException );
558         }
559         else
560         {
561             // is SET
562             typelib_MethodParameter aParam;
563             aParam.pTypeRef =
564                 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
565             aParam.bIn      = sal_True;
566             aParam.bOut     = sal_False;
567 
568             typelib_TypeDescriptionReference * pReturnTypeRef = 0;
569             OUString aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") );
570             typelib_typedescriptionreference_new(
571                 &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
572 
573             // dependent dispatch
574             aVtableSlot.index += 1; // get, then set method
575             cpp_call(
576                 pThis, aVtableSlot, // get, then set method
577                 pReturnTypeRef,
578                 1, &aParam,
579                 pReturn, pArgs, ppException );
580 
581             typelib_typedescriptionreference_release( pReturnTypeRef );
582         }
583 
584         break;
585     }
586     case typelib_TypeClass_INTERFACE_METHOD:
587     {
588 #if OSL_DEBUG_LEVEL > 0
589         // determine vtable call index
590         sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition;
591         OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### member pos out of range!" );
592 #endif
593         VtableSlot aVtableSlot(
594                 getVtableSlot(
595                     reinterpret_cast<
596                     typelib_InterfaceMethodTypeDescription const * >(
597                         pMemberDescr)));
598 
599         switch (aVtableSlot.index)
600         {
601             // standard calls
602         case 1: // acquire uno interface
603             (*pUnoI->acquire)( pUnoI );
604             *ppException = 0;
605             break;
606         case 2: // release uno interface
607             (*pUnoI->release)( pUnoI );
608             *ppException = 0;
609             break;
610         case 0: // queryInterface() opt
611         {
612             typelib_TypeDescription * pTD = 0;
613             TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() );
614             if (pTD)
615             {
616                 uno_Interface * pInterface = 0;
617                 (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)(
618                     pThis->getBridge()->getUnoEnv(),
619                     (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
620 
621                 if (pInterface)
622                 {
623                     ::uno_any_construct(
624                         reinterpret_cast< uno_Any * >( pReturn ),
625                         &pInterface, pTD, 0 );
626                     (*pInterface->release)( pInterface );
627                     TYPELIB_DANGER_RELEASE( pTD );
628                     *ppException = 0;
629                     break;
630                 }
631                 TYPELIB_DANGER_RELEASE( pTD );
632             }
633         } // else perform queryInterface()
634         default:
635             // dependent dispatch
636             cpp_call(
637                 pThis, aVtableSlot,
638                 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef,
639                 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams,
640                 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams,
641                 pReturn, pArgs, ppException );
642         }
643         break;
644     }
645     default:
646     {
647         ::com::sun::star::uno::RuntimeException aExc(
648             OUString( RTL_CONSTASCII_USTRINGPARAM("illegal member type description!") ),
649             ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
650 
651         Type const & rExcType = ::getCppuType( &aExc );
652         // binary identical null reference
653         ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
654     }
655     }
656 }
657 
658 } } }
659