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