xref: /AOO41X/main/bridges/source/cpp_uno/gcc3_macosx_intel/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 <com/sun/star/uno/genfunc.hxx>
32 #include "com/sun/star/uno/RuntimeException.hpp"
33 #include "com/sun/star/uno/Sequence.hxx"
34 #include <uno/data.h>
35 #include <typelib/typedescription.hxx>
36 
37 #include "bridges/cpp_uno/shared/bridge.hxx"
38 #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx"
39 #include "bridges/cpp_uno/shared/types.hxx"
40 #include "bridges/cpp_uno/shared/vtablefactory.hxx"
41 
42 #include "share.hxx"
43 
44 #include "boost/static_assert.hpp"
45 #include <stdio.h>
46 
47 using namespace ::com::sun::star::uno;
48 
49 namespace
50 {
51 
52 //==================================================================================================
53 void cpp2uno_call(
54     bridges::cpp_uno::shared::CppInterfaceProxy * pThis,
55     const typelib_TypeDescription * pMemberTypeDescr,
56     typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return
57     sal_Int32 nParams, typelib_MethodParameter * pParams,
58     void ** pCallStack,
59     void * pReturnValue )
60 {
61     // pCallStack: ret, [return ptr], this, params
62     char * pCppStack = (char *)(pCallStack +1);
63 
64     // return
65     typelib_TypeDescription * pReturnTypeDescr = 0;
66     if (pReturnTypeRef)
67         TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
68 
69     void * pUnoReturn = 0;
70     void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
71 
72     if (pReturnTypeDescr)
73     {
74         // xxx todo: test PolyStructy<STRUCT<long>> foo()
75         if (CPPU_CURRENT_NAMESPACE::isSimpleReturnType( pReturnTypeDescr ))
76         {
77             pUnoReturn = pReturnValue; // direct way for simple types
78         }
79         else // complex return via ptr (pCppReturn)
80         {
81             pCppReturn = *(void **)pCppStack;
82             pCppStack += sizeof(void *);
83             pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType(
84                               pReturnTypeDescr )
85                           ? alloca( pReturnTypeDescr->nSize )
86                           : pCppReturn); // direct way
87         }
88     }
89     // pop this
90     pCppStack += sizeof( void* );
91 
92     // stack space
93     OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" );
94     // parameters
95     void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams );
96     void ** pCppArgs = pUnoArgs + nParams;
97     // indizes of values this have to be converted (interface conversion cpp<=>uno)
98     sal_Int32 * pTempIndizes = (sal_Int32 *)(pUnoArgs + (2 * nParams));
99     // type descriptions for reconversions
100     typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams));
101 
102     sal_Int32 nTempIndizes   = 0;
103 
104     for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
105     {
106         const typelib_MethodParameter & rParam = pParams[nPos];
107         typelib_TypeDescription * pParamTypeDescr = 0;
108         TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
109 
110         if (!rParam.bOut
111             && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
112             // value
113         {
114             pCppArgs[nPos] = pCppStack;
115             pUnoArgs[nPos] = pCppStack;
116             switch (pParamTypeDescr->eTypeClass)
117             {
118             case typelib_TypeClass_HYPER:
119             case typelib_TypeClass_UNSIGNED_HYPER:
120             case typelib_TypeClass_DOUBLE:
121                 pCppStack += sizeof(sal_Int32); // extra long
122             default:
123                 break;
124             }
125             // no longer needed
126             TYPELIB_DANGER_RELEASE( pParamTypeDescr );
127         }
128         else // ptr to complex value | ref
129         {
130             pCppArgs[nPos] = *(void **)pCppStack;
131 
132             if (! rParam.bIn) // is pure out
133             {
134                 // uno out is unconstructed mem!
135                 pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
136                 pTempIndizes[nTempIndizes] = nPos;
137                 // will be released at reconversion
138                 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
139             }
140             // is in/inout
141             else if (bridges::cpp_uno::shared::relatesToInterfaceType(
142                          pParamTypeDescr ))
143             {
144                 uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
145                                         *(void **)pCppStack, pParamTypeDescr,
146                                         pThis->getBridge()->getCpp2Uno() );
147                 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
148                 // will be released at reconversion
149                 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
150             }
151             else // direct way
152             {
153                 pUnoArgs[nPos] = *(void **)pCppStack;
154                 // no longer needed
155                 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
156             }
157         }
158         pCppStack += sizeof(sal_Int32); // standard parameter length
159     }
160 
161     // ExceptionHolder
162     uno_Any aUnoExc; // Any will be constructed by callee
163     uno_Any * pUnoExc = &aUnoExc;
164 
165     // invoke uno dispatch call
166     (*pThis->getUnoI()->pDispatcher)(
167         pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
168 
169     // in case an exception occured...
170     if (pUnoExc)
171     {
172         // destruct temporary in/inout params
173         for ( ; nTempIndizes--; )
174         {
175             sal_Int32 nIndex = pTempIndizes[nTempIndizes];
176 
177             if (pParams[nIndex].bIn) // is in/inout => was constructed
178                 uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], 0 );
179             TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
180         }
181         if (pReturnTypeDescr)
182             TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
183 
184         CPPU_CURRENT_NAMESPACE::raiseException(
185             &aUnoExc, pThis->getBridge()->getUno2Cpp() );
186             // has to destruct the any
187     }
188     else // else no exception occured...
189     {
190         // temporary params
191         for ( ; nTempIndizes--; )
192         {
193             sal_Int32 nIndex = pTempIndizes[nTempIndizes];
194             typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
195 
196             if (pParams[nIndex].bOut) // inout/out
197             {
198                 // convert and assign
199                 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
200                 uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
201                                         pThis->getBridge()->getUno2Cpp() );
202             }
203             // destroy temp uno param
204             uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
205 
206             TYPELIB_DANGER_RELEASE( pParamTypeDescr );
207         }
208         // return
209         if (pCppReturn) // has complex return
210         {
211             if (pUnoReturn != pCppReturn) // needs reconversion
212             {
213                 uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
214                                         pThis->getBridge()->getUno2Cpp() );
215                 // destroy temp uno return
216                 uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
217             }
218             if (pReturnValue != pCppReturn) {
219                 // complex return ptr is set to eax if return value
220                 // is not transferred via eax[/edx]:
221                 *static_cast< void ** >(pReturnValue) = pCppReturn;
222             }
223         }
224         if (pReturnTypeDescr)
225         {
226             TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
227         }
228     }
229 }
230 
231 
232 //==================================================================================================
233 extern "C" void cpp_vtable_call(
234     int nFunctionIndex, int nVtableOffset, void** pCallStack,
235     void * pReturnValue )
236 {
237     OSL_ENSURE( sizeof(sal_Int32)==sizeof(void *), "### unexpected!" );
238 
239     // pCallStack: ret adr, [ret *], this, params
240     void * pThis;
241     if( nFunctionIndex & 0x80000000 )
242     {
243         nFunctionIndex &= 0x7fffffff;
244         pThis = pCallStack[2];
245     }
246     else
247     {
248         pThis = pCallStack[1];
249     }
250     pThis = static_cast< char * >(pThis) - nVtableOffset;
251     bridges::cpp_uno::shared::CppInterfaceProxy * pCppI
252         = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
253             pThis);
254 #if OSL_DEBUG_LEVEL > 1
255     fprintf( stderr, "%p %p %p pThis=%p, pCppI=%p, function index=%d, vtable offset=%d\n", pCallStack[0], pCallStack[1], pCallStack[2], pThis, pCppI, nFunctionIndex, nVtableOffset );
256 #endif
257     typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
258 #if OSL_DEBUG_LEVEL > 1
259     fprintf( stderr, "name=%s\n", rtl::OUStringToOString(pTypeDescr->aBase.pTypeName, RTL_TEXTENCODING_UTF8).getStr() );
260 #endif
261     OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!" );
262     if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
263     {
264         throw RuntimeException(
265             rtl::OUString::createFromAscii("illegal vtable index!"),
266             (XInterface *)pThis );
267     }
268 
269     // determine called method
270     sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
271     OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!" );
272 
273     TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
274 #if OSL_DEBUG_LEVEL > 1
275     fprintf(stderr, "calling %s\n", rtl::OUStringToOString(aMemberDescr.get()->pTypeName, RTL_TEXTENCODING_UTF8).getStr());
276 #endif
277     switch (aMemberDescr.get()->eTypeClass)
278     {
279     case typelib_TypeClass_INTERFACE_ATTRIBUTE:
280     {
281         if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex)
282         {
283             // is GET method
284             cpp2uno_call(
285                 pCppI, aMemberDescr.get(),
286                 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef,
287                 0, 0, // no params
288                 pCallStack, pReturnValue );
289         }
290         else
291         {
292             // is SET method
293             typelib_MethodParameter aParam;
294             aParam.pTypeRef =
295                 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef;
296             aParam.bIn      = sal_True;
297             aParam.bOut     = sal_False;
298 
299             cpp2uno_call(
300                 pCppI, aMemberDescr.get(),
301                 0, // indicates void return
302                 1, &aParam,
303                 pCallStack, pReturnValue );
304         }
305         break;
306     }
307     case typelib_TypeClass_INTERFACE_METHOD:
308     {
309         // is METHOD
310         switch (nFunctionIndex)
311         {
312         case 1: // acquire()
313             pCppI->acquireProxy(); // non virtual call!
314             break;
315         case 2: // release()
316             pCppI->releaseProxy(); // non virtual call!
317             break;
318         case 0: // queryInterface() opt
319         {
320             typelib_TypeDescription * pTD = 0;
321             TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pCallStack[3] )->getTypeLibType() );
322             if (pTD)
323             {
324                 XInterface * pInterface = 0;
325                 (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
326                     pCppI->getBridge()->getCppEnv(),
327                     (void **)&pInterface, pCppI->getOid().pData,
328                     (typelib_InterfaceTypeDescription *)pTD );
329 
330                 if (pInterface)
331                 {
332                     ::uno_any_construct(
333                         reinterpret_cast< uno_Any * >( pCallStack[1] ),
334                         &pInterface, pTD, cpp_acquire );
335                     pInterface->release();
336                     TYPELIB_DANGER_RELEASE( pTD );
337                     *static_cast< void ** >(pReturnValue) = pCallStack[1];
338                     break;
339                 }
340                 TYPELIB_DANGER_RELEASE( pTD );
341             }
342         } // else perform queryInterface()
343         default:
344             cpp2uno_call(
345                 pCppI, aMemberDescr.get(),
346                 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef,
347                 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams,
348                 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams,
349                 pCallStack, pReturnValue );
350         }
351         break;
352     }
353     default:
354     {
355         throw RuntimeException(
356             rtl::OUString::createFromAscii("no member description found!"),
357             (XInterface *)pThis );
358     }
359     }
360 }
361 
362 //==================================================================================================
363 extern "C" void privateSnippetExecutorGeneral();
364 extern "C" void privateSnippetExecutorVoid();
365 extern "C" void privateSnippetExecutorHyper();
366 extern "C" void privateSnippetExecutorFloat();
367 extern "C" void privateSnippetExecutorDouble();
368 extern "C" void privateSnippetExecutorClass();
369 extern "C" typedef void (*PrivateSnippetExecutor)();
370 
371 int const codeSnippetSize = 16;
372 
373 unsigned char * codeSnippet(
374     unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset,
375     typelib_TypeDescriptionReference * pReturnTypeRef)
376 {
377     PrivateSnippetExecutor exec;
378     if (pReturnTypeRef == 0) {
379         exec = privateSnippetExecutorVoid;
380     }
381     else {
382         switch (pReturnTypeRef->eTypeClass) {
383         case typelib_TypeClass_VOID:
384             exec = privateSnippetExecutorVoid;
385             break;
386         case typelib_TypeClass_HYPER:
387         case typelib_TypeClass_UNSIGNED_HYPER:
388             exec = privateSnippetExecutorHyper;
389             break;
390         case typelib_TypeClass_FLOAT:
391             exec = privateSnippetExecutorFloat;
392             break;
393         case typelib_TypeClass_DOUBLE:
394             exec = privateSnippetExecutorDouble;
395             break;
396         case typelib_TypeClass_STRUCT:
397         case typelib_TypeClass_EXCEPTION: {
398             typelib_TypeDescription * pReturnTypeDescr = 0;
399             TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
400             bool const bSimpleReturnStruct =
401                 CPPU_CURRENT_NAMESPACE::isSimpleReturnType(pReturnTypeDescr);
402             sal_Int32 const nRetSize = pReturnTypeDescr->nSize;
403             TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
404             if (bSimpleReturnStruct && nRetSize <= 8) {
405                 exec = privateSnippetExecutorGeneral; // fills eax
406                 if (nRetSize > 4)
407                     exec = privateSnippetExecutorHyper; // fills eax/edx
408                 break;
409             }
410         }
411         case typelib_TypeClass_STRING:
412         case typelib_TypeClass_TYPE:
413         case typelib_TypeClass_SEQUENCE:
414         case typelib_TypeClass_INTERFACE:
415         case typelib_TypeClass_ANY:
416             functionIndex |= 0x80000000;
417             exec = privateSnippetExecutorClass;
418             break;
419         default:
420             exec = privateSnippetExecutorGeneral;
421             break;
422         }
423     }
424     unsigned char * p = code;
425     OSL_ASSERT(sizeof (sal_Int32) == 4);
426     // mov function_index, %eax:
427     *p++ = 0xB8;
428     *reinterpret_cast< sal_Int32 * >(p) = functionIndex;
429     p += sizeof (sal_Int32);
430     // mov vtable_offset, %edx:
431     *p++ = 0xBA;
432     *reinterpret_cast< sal_Int32 * >(p) = vtableOffset;
433     p += sizeof (sal_Int32);
434     // jmp privateSnippetExecutor:
435     *p++ = 0xE9;
436     *reinterpret_cast< sal_Int32 * >(p)
437         = ((unsigned char *) exec) - p - sizeof (sal_Int32);
438     p += sizeof (sal_Int32);
439     OSL_ASSERT(p - code <= codeSnippetSize);
440     return code + codeSnippetSize;
441 }
442 
443 }
444 
445 struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; };
446 
447 bridges::cpp_uno::shared::VtableFactory::Slot *
448 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
449 {
450     return static_cast< Slot * >(block) + 2;
451 }
452 
453 sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize(
454     sal_Int32 slotCount)
455 {
456     return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
457 }
458 
459 bridges::cpp_uno::shared::VtableFactory::Slot *
460 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
461     void * block, sal_Int32 slotCount)
462 {
463     Slot * slots = mapBlockToVtable(block);
464     slots[-2].fn = 0;
465     slots[-1].fn = 0;
466     return slots + slotCount;
467 }
468 
469 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
470     Slot ** slots, unsigned char * code,
471     typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
472     sal_Int32 functionCount, sal_Int32 vtableOffset)
473 {
474     (*slots) -= functionCount;
475     Slot * s = *slots;
476     for (sal_Int32 i = 0; i < type->nMembers; ++i) {
477         typelib_TypeDescription * member = 0;
478         TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
479         OSL_ASSERT(member != 0);
480         switch (member->eTypeClass) {
481         case typelib_TypeClass_INTERFACE_ATTRIBUTE:
482             // Getter:
483             (s++)->fn = code;
484             code = codeSnippet(
485                 code, functionOffset++, vtableOffset,
486                 reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >(
487                     member)->pAttributeTypeRef);
488             // Setter:
489             if (!reinterpret_cast<
490                 typelib_InterfaceAttributeTypeDescription * >(
491                     member)->bReadOnly)
492             {
493                 (s++)->fn = code;
494                 code = codeSnippet(
495                     code, functionOffset++, vtableOffset,
496                     0 /* indicates VOID */);
497             }
498             break;
499 
500         case typelib_TypeClass_INTERFACE_METHOD:
501             (s++)->fn = code;
502             code = codeSnippet(
503                 code, functionOffset++, vtableOffset,
504                 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
505                     member)->pReturnTypeRef);
506             break;
507 
508         default:
509             OSL_ASSERT(false);
510             break;
511         }
512         TYPELIB_DANGER_RELEASE(member);
513     }
514     return code;
515 }
516 
517 void bridges::cpp_uno::shared::VtableFactory::flushCode(
518     unsigned char const *, unsigned char const *)
519 {}
520