xref: /trunk/main/bridges/source/cpp_uno/gcc3_freebsd_x86-64/cpp2uno.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_bridges.hxx"
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <hash_map>
34 
35 #include <rtl/alloc.h>
36 #include <osl/mutex.hxx>
37 
38 #include <com/sun/star/uno/genfunc.hxx>
39 #include "com/sun/star/uno/RuntimeException.hpp"
40 #include <uno/data.h>
41 #include <typelib/typedescription.hxx>
42 
43 #include "bridges/cpp_uno/shared/bridge.hxx"
44 #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx"
45 #include "bridges/cpp_uno/shared/types.hxx"
46 #include "bridges/cpp_uno/shared/vtablefactory.hxx"
47 
48 #include "abi.hxx"
49 #include "share.hxx"
50 
51 using namespace ::osl;
52 using namespace ::rtl;
53 using namespace ::com::sun::star::uno;
54 
55 //==================================================================================================
56 
57 // Perform the UNO call
58 //
59 // We must convert the paramaters stored in gpreg, fpreg and ovrflw to UNO
60 // arguments and call pThis->getUnoI()->pDispatcher.
61 //
62 // gpreg:  [ret *], this, [gpr params]
63 // fpreg:  [fpr params]
64 // ovrflw: [gpr or fpr params (properly aligned)]
65 //
66 // [ret *] is present when we are returning a structure bigger than 16 bytes
67 // Simple types are returned in rax, rdx (int), or xmm0, xmm1 (fp).
68 // Similarly structures <= 16 bytes are in rax, rdx, xmm0, xmm1 as necessary.
69 static typelib_TypeClass cpp2uno_call(
70     bridges::cpp_uno::shared::CppInterfaceProxy * pThis,
71     const typelib_TypeDescription * pMemberTypeDescr,
72     typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return
73     sal_Int32 nParams, typelib_MethodParameter * pParams,
74     void ** gpreg, void ** fpreg, void ** ovrflw,
75     sal_uInt64 * pRegisterReturn /* space for register return */ )
76 {
77     int nr_gpr = 0; //number of gpr registers used
78     int nr_fpr = 0; //number of fpr regsiters used
79 
80     // return
81     typelib_TypeDescription * pReturnTypeDescr = 0;
82     if (pReturnTypeRef)
83         TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
84 
85     void * pUnoReturn = 0;
86     void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
87 
88     if ( pReturnTypeDescr )
89     {
90         if ( x86_64::return_in_hidden_param( pReturnTypeRef ) )
91         {
92             pCppReturn = *gpreg++;
93             nr_gpr++;
94 
95             pUnoReturn = ( bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
96                            ? alloca( pReturnTypeDescr->nSize )
97                            : pCppReturn ); // direct way
98         }
99         else
100             pUnoReturn = pRegisterReturn; // direct way for simple types
101     }
102 
103     // pop this
104     gpreg++;
105     nr_gpr++;
106 
107     // stack space
108     // parameters
109     void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams );
110     void ** pCppArgs = pUnoArgs + nParams;
111     // indizes of values this have to be converted (interface conversion cpp<=>uno)
112     sal_Int32 * pTempIndizes = (sal_Int32 *)(pUnoArgs + (2 * nParams));
113     // type descriptions for reconversions
114     typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams));
115 
116     sal_Int32 nTempIndizes = 0;
117 
118     for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
119     {
120         const typelib_MethodParameter & rParam = pParams[nPos];
121         typelib_TypeDescription * pParamTypeDescr = 0;
122         TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
123 
124         int nUsedGPR = 0;
125         int nUsedSSE = 0;
126         bool bFitsRegisters = x86_64::examine_argument( rParam.pTypeRef, false, nUsedGPR, nUsedSSE );
127         if ( !rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ) ) // value
128         {
129             // Simple types must fit exactly one register on x86_64
130             OSL_ASSERT( bFitsRegisters && ( ( nUsedSSE == 1 && nUsedGPR == 0 ) || ( nUsedSSE == 0 && nUsedGPR == 1 ) ) );
131 
132             if ( nUsedSSE == 1 )
133             {
134                 if ( nr_fpr < x86_64::MAX_SSE_REGS )
135                 {
136                     pCppArgs[nPos] = pUnoArgs[nPos] = fpreg++;
137                     nr_fpr++;
138                 }
139                 else
140                     pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw++;
141             }
142             else if ( nUsedGPR == 1 )
143             {
144                 if ( nr_gpr < x86_64::MAX_GPR_REGS )
145                 {
146                     pCppArgs[nPos] = pUnoArgs[nPos] = gpreg++;
147                     nr_gpr++;
148                 }
149                 else
150                     pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw++;
151             }
152 
153             // no longer needed
154             TYPELIB_DANGER_RELEASE( pParamTypeDescr );
155         }
156         else // struct <= 16 bytes || ptr to complex value || ref
157         {
158             void *pCppStack;
159             char pTmpStruct[16];
160 
161             if ( bFitsRegisters && !rParam.bOut &&
162                  ( pParamTypeDescr->eTypeClass == typelib_TypeClass_STRUCT ||
163                    pParamTypeDescr->eTypeClass == typelib_TypeClass_EXCEPTION ) )
164             {
165                 if ( ( nr_gpr + nUsedGPR <= x86_64::MAX_GPR_REGS ) && ( nr_fpr + nUsedSSE <= x86_64::MAX_SSE_REGS ) )
166                 {
167                     x86_64::fill_struct( rParam.pTypeRef, gpreg, fpreg, pTmpStruct );
168 #if OSL_DEBUG_LEVEL > 1
169                     fprintf( stderr, "nUsedGPR == %d, nUsedSSE == %d, pTmpStruct[0] == 0x%x, pTmpStruct[1] == 0x%x, **gpreg == 0x%lx\n",
170                             nUsedGPR, nUsedSSE, pTmpStruct[0], pTmpStruct[1], *(sal_uInt64*)*gpreg );
171 #endif
172 
173                     pCppArgs[nPos] = pCppStack = reinterpret_cast<void *>( pTmpStruct );
174                     gpreg += nUsedGPR;
175                     fpreg += nUsedSSE;
176                 }
177                 else
178                     pCppArgs[nPos] = pCppStack = *ovrflw++;
179             }
180             else if ( nr_gpr < x86_64::MAX_GPR_REGS )
181             {
182                 pCppArgs[nPos] = pCppStack = *gpreg++;
183                 nr_gpr++;
184             }
185             else
186                 pCppArgs[nPos] = pCppStack = *ovrflw++;
187 
188             if (! rParam.bIn) // is pure out
189             {
190                 // uno out is unconstructed mem!
191                 pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
192                 pTempIndizes[nTempIndizes] = nPos;
193                 // will be released at reconversion
194                 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
195             }
196             else if ( bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ) ) // is in/inout
197             {
198                 uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
199                                         pCppStack, pParamTypeDescr,
200                                         pThis->getBridge()->getCpp2Uno() );
201                 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
202                 // will be released at reconversion
203                 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
204             }
205             else // direct way
206             {
207                 pUnoArgs[nPos] = pCppStack;
208                 // no longer needed
209                 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
210             }
211         }
212     }
213 
214     // ExceptionHolder
215     uno_Any aUnoExc; // Any will be constructed by callee
216     uno_Any * pUnoExc = &aUnoExc;
217 
218     // invoke uno dispatch call
219     (*pThis->getUnoI()->pDispatcher)( pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
220 
221     // in case an exception occured...
222     if ( pUnoExc )
223     {
224         // destruct temporary in/inout params
225         for ( ; nTempIndizes--; )
226         {
227             sal_Int32 nIndex = pTempIndizes[nTempIndizes];
228 
229             if (pParams[nIndex].bIn) // is in/inout => was constructed
230                 uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], 0 );
231             TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
232         }
233         if (pReturnTypeDescr)
234             TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
235 
236         CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc, pThis->getBridge()->getUno2Cpp() ); // has to destruct the any
237         // is here for dummy
238         return typelib_TypeClass_VOID;
239     }
240     else // else no exception occured...
241     {
242         // temporary params
243         for ( ; nTempIndizes--; )
244         {
245             sal_Int32 nIndex = pTempIndizes[nTempIndizes];
246             typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
247 
248             if ( pParams[nIndex].bOut ) // inout/out
249             {
250                 // convert and assign
251                 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
252                 uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
253                                         pThis->getBridge()->getUno2Cpp() );
254             }
255             // destroy temp uno param
256             uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
257 
258             TYPELIB_DANGER_RELEASE( pParamTypeDescr );
259         }
260         // return
261         if ( pCppReturn ) // has complex return
262         {
263             if ( pUnoReturn != pCppReturn ) // needs reconversion
264             {
265                 uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
266                                         pThis->getBridge()->getUno2Cpp() );
267                 // destroy temp uno return
268                 uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
269             }
270             // complex return ptr is set to return reg
271             *(void **)pRegisterReturn = pCppReturn;
272         }
273         if ( pReturnTypeDescr )
274         {
275             typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
276             TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
277             return eRet;
278         }
279         else
280             return typelib_TypeClass_VOID;
281     }
282 }
283 
284 
285 //==================================================================================================
286 extern "C" typelib_TypeClass cpp_vtable_call(
287     sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
288     void ** gpreg, void ** fpreg, void ** ovrflw,
289     sal_uInt64 * pRegisterReturn /* space for register return */ )
290 {
291     // gpreg:  [ret *], this, [other gpr params]
292     // fpreg:  [fpr params]
293     // ovrflw: [gpr or fpr params (properly aligned)]
294     void * pThis;
295     if ( nFunctionIndex & 0x80000000 )
296     {
297         nFunctionIndex &= 0x7fffffff;
298         pThis = gpreg[1];
299     }
300     else
301     {
302         pThis = gpreg[0];
303     }
304     pThis = static_cast<char *>( pThis ) - nVtableOffset;
305 
306     bridges::cpp_uno::shared::CppInterfaceProxy * pCppI =
307         bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( pThis );
308 
309     typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
310 
311     OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!\n" );
312     if ( nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex )
313     {
314         throw RuntimeException( OUString::createFromAscii("illegal vtable index!"),
315                                 reinterpret_cast<XInterface *>( pCppI ) );
316     }
317 
318     // determine called method
319     sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
320     OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!\n" );
321 
322     TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
323 
324     typelib_TypeClass eRet;
325     switch ( aMemberDescr.get()->eTypeClass )
326     {
327         case typelib_TypeClass_INTERFACE_ATTRIBUTE:
328         {
329             typelib_TypeDescriptionReference *pAttrTypeRef =
330                 reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( aMemberDescr.get() )->pAttributeTypeRef;
331 
332             if ( pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex )
333             {
334                 // is GET method
335                 eRet = cpp2uno_call( pCppI, aMemberDescr.get(), pAttrTypeRef,
336                         0, 0, // no params
337                         gpreg, fpreg, ovrflw, pRegisterReturn );
338             }
339             else
340             {
341                 // is SET method
342                 typelib_MethodParameter aParam;
343                 aParam.pTypeRef = pAttrTypeRef;
344                 aParam.bIn      = sal_True;
345                 aParam.bOut     = sal_False;
346 
347                 eRet = cpp2uno_call( pCppI, aMemberDescr.get(),
348                         0, // indicates void return
349                         1, &aParam,
350                         gpreg, fpreg, ovrflw, pRegisterReturn );
351             }
352             break;
353         }
354         case typelib_TypeClass_INTERFACE_METHOD:
355         {
356             // is METHOD
357             switch ( nFunctionIndex )
358             {
359                 case 1: // acquire()
360                     pCppI->acquireProxy(); // non virtual call!
361                     eRet = typelib_TypeClass_VOID;
362                     break;
363                 case 2: // release()
364                     pCppI->releaseProxy(); // non virtual call!
365                     eRet = typelib_TypeClass_VOID;
366                     break;
367                 case 0: // queryInterface() opt
368                 {
369                     typelib_TypeDescription * pTD = 0;
370                     TYPELIB_DANGER_GET( &pTD, reinterpret_cast<Type *>( gpreg[2] )->getTypeLibType() );
371                     if ( pTD )
372                     {
373                         XInterface * pInterface = 0;
374                         (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)
375                             ( pCppI->getBridge()->getCppEnv(),
376                               (void **)&pInterface,
377                               pCppI->getOid().pData,
378                               reinterpret_cast<typelib_InterfaceTypeDescription *>( pTD ) );
379 
380                         if ( pInterface )
381                         {
382                             ::uno_any_construct( reinterpret_cast<uno_Any *>( gpreg[0] ),
383                                                  &pInterface, pTD, cpp_acquire );
384 
385                             pInterface->release();
386                             TYPELIB_DANGER_RELEASE( pTD );
387 
388                             reinterpret_cast<void **>( pRegisterReturn )[0] = gpreg[0];
389                             eRet = typelib_TypeClass_ANY;
390                             break;
391                         }
392                         TYPELIB_DANGER_RELEASE( pTD );
393                     }
394                 } // else perform queryInterface()
395                 default:
396                 {
397                     typelib_InterfaceMethodTypeDescription *pMethodTD =
398                         reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( aMemberDescr.get() );
399 
400                     eRet = cpp2uno_call( pCppI, aMemberDescr.get(),
401                                          pMethodTD->pReturnTypeRef,
402                                          pMethodTD->nParams,
403                                          pMethodTD->pParams,
404                                          gpreg, fpreg, ovrflw, pRegisterReturn );
405                 }
406             }
407             break;
408         }
409         default:
410         {
411             throw RuntimeException( OUString::createFromAscii("no member description found!"),
412                                     reinterpret_cast<XInterface *>( pCppI ) );
413             // is here for dummy
414             eRet = typelib_TypeClass_VOID;
415         }
416     }
417 
418     return eRet;
419 }
420 
421 //==================================================================================================
422 extern "C" void privateSnippetExecutor( ... );
423 
424 const int codeSnippetSize = 24;
425 
426 // Generate a trampoline that redirects method calls to
427 // privateSnippetExecutor().
428 //
429 // privateSnippetExecutor() saves all the registers that are used for
430 // parameter passing on x86_64, and calls the cpp_vtable_call().
431 // When it returns, privateSnippetExecutor() sets the return value.
432 //
433 // Note: The code snippet we build here must not create a stack frame,
434 // otherwise the UNO exceptions stop working thanks to non-existing
435 // unwinding info.
436 unsigned char * codeSnippet( unsigned char * code,
437         sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
438         bool bHasHiddenParam ) SAL_THROW( () )
439 {
440     sal_uInt64 nOffsetAndIndex = ( ( (sal_uInt64) nVtableOffset ) << 32 ) | ( (sal_uInt64) nFunctionIndex );
441 
442     if ( bHasHiddenParam )
443         nOffsetAndIndex |= 0x80000000;
444 
445     // movq $<nOffsetAndIndex>, %r10
446     *reinterpret_cast<sal_uInt16 *>( code ) = 0xba49;
447     *reinterpret_cast<sal_uInt64 *>( code + 2 ) = nOffsetAndIndex;
448 
449     // movq $<address of the privateSnippetExecutor>, %r11
450     *reinterpret_cast<sal_uInt16 *>( code + 10 ) = 0xbb49;
451     *reinterpret_cast<sal_uInt64 *>( code + 12 ) = reinterpret_cast<sal_uInt64>( privateSnippetExecutor );
452 
453     // jmpq *%r11
454     *reinterpret_cast<sal_uInt32 *>( code + 20 ) = 0x00e3ff49;
455 
456     return code + codeSnippetSize;
457 }
458 
459 //==================================================================================================
460 struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; };
461 
462 bridges::cpp_uno::shared::VtableFactory::Slot *
463 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
464 {
465     return static_cast< Slot * >(block) + 2;
466 }
467 
468 //==================================================================================================
469 sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize(
470     sal_Int32 slotCount)
471 {
472     return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
473 }
474 
475 //==================================================================================================
476 bridges::cpp_uno::shared::VtableFactory::Slot *
477 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
478     void * block, sal_Int32 slotCount)
479 {
480     Slot * slots = mapBlockToVtable(block);
481     slots[-2].fn = 0;
482     slots[-1].fn = 0;
483     return slots + slotCount;
484 }
485 
486 //==================================================================================================
487 
488 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
489     Slot ** slots, unsigned char * code,
490     typelib_InterfaceTypeDescription const * type, sal_Int32 nFunctionOffset,
491     sal_Int32 functionCount, sal_Int32 nVtableOffset )
492 {
493     (*slots) -= functionCount;
494     Slot * s = *slots;
495 
496     for ( sal_Int32 nPos = 0; nPos < type->nMembers; ++nPos )
497     {
498         typelib_TypeDescription * pTD = 0;
499 
500         TYPELIB_DANGER_GET( &pTD, type->ppMembers[ nPos ] );
501         OSL_ASSERT( pTD );
502 
503         if ( typelib_TypeClass_INTERFACE_ATTRIBUTE == pTD->eTypeClass )
504         {
505             typelib_InterfaceAttributeTypeDescription *pAttrTD =
506                 reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( pTD );
507 
508             // get method
509             (s++)->fn = code;
510             code = codeSnippet( code, nFunctionOffset++, nVtableOffset,
511                                 x86_64::return_in_hidden_param( pAttrTD->pAttributeTypeRef ) );
512 
513             if ( ! pAttrTD->bReadOnly )
514             {
515                 // set method
516                 (s++)->fn = code;
517                 code = codeSnippet( code, nFunctionOffset++, nVtableOffset, false );
518             }
519         }
520         else if ( typelib_TypeClass_INTERFACE_METHOD == pTD->eTypeClass )
521         {
522             typelib_InterfaceMethodTypeDescription *pMethodTD =
523                 reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( pTD );
524 
525             (s++)->fn = code;
526             code = codeSnippet( code, nFunctionOffset++, nVtableOffset,
527                                 x86_64::return_in_hidden_param( pMethodTD->pReturnTypeRef ) );
528         }
529         else
530             OSL_ASSERT( false );
531 
532         TYPELIB_DANGER_RELEASE( pTD );
533     }
534     return code;
535 }
536 
537 //==================================================================================================
538 void bridges::cpp_uno::shared::VtableFactory::flushCode(
539     unsigned char const *, unsigned char const * )
540 {
541 }
542