Update ooo320-m1
[ooovba.git] / bridges / source / cpp_uno / gcc3_macosx_intel / cpp2uno.cxx
blob155d35b2fb1631585ebfa890eaef96345d13ed6b
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: cpp2uno.cxx,v $
10 * $Revision: 1.7 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_bridges.hxx"
34 #include <com/sun/star/uno/genfunc.hxx>
35 #include "com/sun/star/uno/RuntimeException.hpp"
36 #include "com/sun/star/uno/Sequence.hxx"
37 #include <uno/data.h>
38 #include <typelib/typedescription.hxx>
40 #include "bridges/cpp_uno/shared/bridge.hxx"
41 #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx"
42 #include "bridges/cpp_uno/shared/types.hxx"
43 #include "bridges/cpp_uno/shared/vtablefactory.hxx"
45 #include "share.hxx"
47 #include "boost/static_assert.hpp"
48 #include <stdio.h>
50 using namespace ::com::sun::star::uno;
52 namespace
55 //==================================================================================================
56 void cpp2uno_call(
57 bridges::cpp_uno::shared::CppInterfaceProxy * pThis,
58 const typelib_TypeDescription * pMemberTypeDescr,
59 typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return
60 sal_Int32 nParams, typelib_MethodParameter * pParams,
61 void ** pCallStack,
62 void * pReturnValue )
64 // pCallStack: ret, [return ptr], this, params
65 char * pCppStack = (char *)(pCallStack +1);
67 // return
68 typelib_TypeDescription * pReturnTypeDescr = 0;
69 if (pReturnTypeRef)
70 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
72 void * pUnoReturn = 0;
73 void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
75 if (pReturnTypeDescr)
77 // xxx todo: test PolyStructy<STRUCT<long>> foo()
78 if (CPPU_CURRENT_NAMESPACE::isSimpleReturnType( pReturnTypeDescr ))
80 pUnoReturn = pReturnValue; // direct way for simple types
82 else // complex return via ptr (pCppReturn)
84 pCppReturn = *(void **)pCppStack;
85 pCppStack += sizeof(void *);
86 pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType(
87 pReturnTypeDescr )
88 ? alloca( pReturnTypeDescr->nSize )
89 : pCppReturn); // direct way
92 // pop this
93 pCppStack += sizeof( void* );
95 // stack space
96 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" );
97 // parameters
98 void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams );
99 void ** pCppArgs = pUnoArgs + nParams;
100 // indizes of values this have to be converted (interface conversion cpp<=>uno)
101 sal_Int32 * pTempIndizes = (sal_Int32 *)(pUnoArgs + (2 * nParams));
102 // type descriptions for reconversions
103 typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams));
105 sal_Int32 nTempIndizes = 0;
107 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
109 const typelib_MethodParameter & rParam = pParams[nPos];
110 typelib_TypeDescription * pParamTypeDescr = 0;
111 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
113 if (!rParam.bOut
114 && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
115 // value
117 pCppArgs[nPos] = pCppStack;
118 pUnoArgs[nPos] = pCppStack;
119 switch (pParamTypeDescr->eTypeClass)
121 case typelib_TypeClass_HYPER:
122 case typelib_TypeClass_UNSIGNED_HYPER:
123 case typelib_TypeClass_DOUBLE:
124 pCppStack += sizeof(sal_Int32); // extra long
125 default:
126 break;
128 // no longer needed
129 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
131 else // ptr to complex value | ref
133 pCppArgs[nPos] = *(void **)pCppStack;
135 if (! rParam.bIn) // is pure out
137 // uno out is unconstructed mem!
138 pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
139 pTempIndizes[nTempIndizes] = nPos;
140 // will be released at reconversion
141 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
143 // is in/inout
144 else if (bridges::cpp_uno::shared::relatesToInterfaceType(
145 pParamTypeDescr ))
147 uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
148 *(void **)pCppStack, pParamTypeDescr,
149 pThis->getBridge()->getCpp2Uno() );
150 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
151 // will be released at reconversion
152 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
154 else // direct way
156 pUnoArgs[nPos] = *(void **)pCppStack;
157 // no longer needed
158 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
161 pCppStack += sizeof(sal_Int32); // standard parameter length
164 // ExceptionHolder
165 uno_Any aUnoExc; // Any will be constructed by callee
166 uno_Any * pUnoExc = &aUnoExc;
168 // invoke uno dispatch call
169 (*pThis->getUnoI()->pDispatcher)(
170 pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
172 // in case an exception occured...
173 if (pUnoExc)
175 // destruct temporary in/inout params
176 for ( ; nTempIndizes--; )
178 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
180 if (pParams[nIndex].bIn) // is in/inout => was constructed
181 uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], 0 );
182 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
184 if (pReturnTypeDescr)
185 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
187 CPPU_CURRENT_NAMESPACE::raiseException(
188 &aUnoExc, pThis->getBridge()->getUno2Cpp() );
189 // has to destruct the any
191 else // else no exception occured...
193 // temporary params
194 for ( ; nTempIndizes--; )
196 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
197 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
199 if (pParams[nIndex].bOut) // inout/out
201 // convert and assign
202 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
203 uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
204 pThis->getBridge()->getUno2Cpp() );
206 // destroy temp uno param
207 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
209 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
211 // return
212 if (pCppReturn) // has complex return
214 if (pUnoReturn != pCppReturn) // needs reconversion
216 uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
217 pThis->getBridge()->getUno2Cpp() );
218 // destroy temp uno return
219 uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
221 if (pReturnValue != pCppReturn) {
222 // complex return ptr is set to eax if return value
223 // is not transferred via eax[/edx]:
224 *static_cast< void ** >(pReturnValue) = pCppReturn;
227 if (pReturnTypeDescr)
229 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
235 //==================================================================================================
236 extern "C" void cpp_vtable_call(
237 int nFunctionIndex, int nVtableOffset, void** pCallStack,
238 void * pReturnValue )
240 OSL_ENSURE( sizeof(sal_Int32)==sizeof(void *), "### unexpected!" );
242 // pCallStack: ret adr, [ret *], this, params
243 void * pThis;
244 if( nFunctionIndex & 0x80000000 )
246 nFunctionIndex &= 0x7fffffff;
247 pThis = pCallStack[2];
249 else
251 pThis = pCallStack[1];
253 pThis = static_cast< char * >(pThis) - nVtableOffset;
254 bridges::cpp_uno::shared::CppInterfaceProxy * pCppI
255 = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
256 pThis);
257 #if OSL_DEBUG_LEVEL > 1
258 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 );
259 #endif
260 typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
261 #if OSL_DEBUG_LEVEL > 1
262 fprintf( stderr, "name=%s\n", rtl::OUStringToOString(pTypeDescr->aBase.pTypeName, RTL_TEXTENCODING_UTF8).getStr() );
263 #endif
264 OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!" );
265 if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
267 throw RuntimeException(
268 rtl::OUString::createFromAscii("illegal vtable index!"),
269 (XInterface *)pThis );
272 // determine called method
273 sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
274 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!" );
276 TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
277 #if OSL_DEBUG_LEVEL > 1
278 fprintf(stderr, "calling %s\n", rtl::OUStringToOString(aMemberDescr.get()->pTypeName, RTL_TEXTENCODING_UTF8).getStr());
279 #endif
280 switch (aMemberDescr.get()->eTypeClass)
282 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
284 if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex)
286 // is GET method
287 cpp2uno_call(
288 pCppI, aMemberDescr.get(),
289 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef,
290 0, 0, // no params
291 pCallStack, pReturnValue );
293 else
295 // is SET method
296 typelib_MethodParameter aParam;
297 aParam.pTypeRef =
298 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef;
299 aParam.bIn = sal_True;
300 aParam.bOut = sal_False;
302 cpp2uno_call(
303 pCppI, aMemberDescr.get(),
304 0, // indicates void return
305 1, &aParam,
306 pCallStack, pReturnValue );
308 break;
310 case typelib_TypeClass_INTERFACE_METHOD:
312 // is METHOD
313 switch (nFunctionIndex)
315 case 1: // acquire()
316 pCppI->acquireProxy(); // non virtual call!
317 break;
318 case 2: // release()
319 pCppI->releaseProxy(); // non virtual call!
320 break;
321 case 0: // queryInterface() opt
323 typelib_TypeDescription * pTD = 0;
324 TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pCallStack[3] )->getTypeLibType() );
325 if (pTD)
327 XInterface * pInterface = 0;
328 (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
329 pCppI->getBridge()->getCppEnv(),
330 (void **)&pInterface, pCppI->getOid().pData,
331 (typelib_InterfaceTypeDescription *)pTD );
333 if (pInterface)
335 ::uno_any_construct(
336 reinterpret_cast< uno_Any * >( pCallStack[1] ),
337 &pInterface, pTD, cpp_acquire );
338 pInterface->release();
339 TYPELIB_DANGER_RELEASE( pTD );
340 *static_cast< void ** >(pReturnValue) = pCallStack[1];
341 break;
343 TYPELIB_DANGER_RELEASE( pTD );
345 } // else perform queryInterface()
346 default:
347 cpp2uno_call(
348 pCppI, aMemberDescr.get(),
349 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef,
350 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams,
351 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams,
352 pCallStack, pReturnValue );
354 break;
356 default:
358 throw RuntimeException(
359 rtl::OUString::createFromAscii("no member description found!"),
360 (XInterface *)pThis );
365 //==================================================================================================
366 extern "C" void privateSnippetExecutorGeneral();
367 extern "C" void privateSnippetExecutorVoid();
368 extern "C" void privateSnippetExecutorHyper();
369 extern "C" void privateSnippetExecutorFloat();
370 extern "C" void privateSnippetExecutorDouble();
371 extern "C" void privateSnippetExecutorClass();
372 extern "C" typedef void (*PrivateSnippetExecutor)();
374 int const codeSnippetSize = 16;
376 unsigned char * codeSnippet(
377 unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset,
378 typelib_TypeDescriptionReference * pReturnTypeRef)
380 PrivateSnippetExecutor exec;
381 if (pReturnTypeRef == 0) {
382 exec = privateSnippetExecutorVoid;
384 else {
385 switch (pReturnTypeRef->eTypeClass) {
386 case typelib_TypeClass_VOID:
387 exec = privateSnippetExecutorVoid;
388 break;
389 case typelib_TypeClass_HYPER:
390 case typelib_TypeClass_UNSIGNED_HYPER:
391 exec = privateSnippetExecutorHyper;
392 break;
393 case typelib_TypeClass_FLOAT:
394 exec = privateSnippetExecutorFloat;
395 break;
396 case typelib_TypeClass_DOUBLE:
397 exec = privateSnippetExecutorDouble;
398 break;
399 case typelib_TypeClass_STRUCT:
400 case typelib_TypeClass_EXCEPTION: {
401 typelib_TypeDescription * pReturnTypeDescr = 0;
402 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
403 bool const bSimpleReturnStruct =
404 CPPU_CURRENT_NAMESPACE::isSimpleReturnType(pReturnTypeDescr);
405 sal_Int32 const nRetSize = pReturnTypeDescr->nSize;
406 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
407 if (bSimpleReturnStruct && nRetSize <= 8) {
408 exec = privateSnippetExecutorGeneral; // fills eax
409 if (nRetSize > 4)
410 exec = privateSnippetExecutorHyper; // fills eax/edx
411 break;
414 case typelib_TypeClass_STRING:
415 case typelib_TypeClass_TYPE:
416 case typelib_TypeClass_SEQUENCE:
417 case typelib_TypeClass_INTERFACE:
418 case typelib_TypeClass_ANY:
419 functionIndex |= 0x80000000;
420 exec = privateSnippetExecutorClass;
421 break;
422 default:
423 exec = privateSnippetExecutorGeneral;
424 break;
427 unsigned char * p = code;
428 OSL_ASSERT(sizeof (sal_Int32) == 4);
429 // mov function_index, %eax:
430 *p++ = 0xB8;
431 *reinterpret_cast< sal_Int32 * >(p) = functionIndex;
432 p += sizeof (sal_Int32);
433 // mov vtable_offset, %edx:
434 *p++ = 0xBA;
435 *reinterpret_cast< sal_Int32 * >(p) = vtableOffset;
436 p += sizeof (sal_Int32);
437 // jmp privateSnippetExecutor:
438 *p++ = 0xE9;
439 *reinterpret_cast< sal_Int32 * >(p)
440 = ((unsigned char *) exec) - p - sizeof (sal_Int32);
441 p += sizeof (sal_Int32);
442 OSL_ASSERT(p - code <= codeSnippetSize);
443 return code + codeSnippetSize;
448 struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; };
450 bridges::cpp_uno::shared::VtableFactory::Slot *
451 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
453 return static_cast< Slot * >(block) + 2;
456 sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize(
457 sal_Int32 slotCount)
459 return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
462 bridges::cpp_uno::shared::VtableFactory::Slot *
463 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
464 void * block, sal_Int32 slotCount)
466 Slot * slots = mapBlockToVtable(block);
467 slots[-2].fn = 0;
468 slots[-1].fn = 0;
469 return slots + slotCount;
472 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
473 Slot ** slots, unsigned char * code,
474 typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
475 sal_Int32 functionCount, sal_Int32 vtableOffset)
477 (*slots) -= functionCount;
478 Slot * s = *slots;
479 for (sal_Int32 i = 0; i < type->nMembers; ++i) {
480 typelib_TypeDescription * member = 0;
481 TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
482 OSL_ASSERT(member != 0);
483 switch (member->eTypeClass) {
484 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
485 // Getter:
486 (s++)->fn = code;
487 code = codeSnippet(
488 code, functionOffset++, vtableOffset,
489 reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >(
490 member)->pAttributeTypeRef);
491 // Setter:
492 if (!reinterpret_cast<
493 typelib_InterfaceAttributeTypeDescription * >(
494 member)->bReadOnly)
496 (s++)->fn = code;
497 code = codeSnippet(
498 code, functionOffset++, vtableOffset,
499 0 /* indicates VOID */);
501 break;
503 case typelib_TypeClass_INTERFACE_METHOD:
504 (s++)->fn = code;
505 code = codeSnippet(
506 code, functionOffset++, vtableOffset,
507 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
508 member)->pReturnTypeRef);
509 break;
511 default:
512 OSL_ASSERT(false);
513 break;
515 TYPELIB_DANGER_RELEASE(member);
517 return code;
520 void bridges::cpp_uno::shared::VtableFactory::flushCode(
521 unsigned char const *, unsigned char const *)