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