Update ooo320-m1
[ooovba.git] / bridges / source / cpp_uno / gcc3_netbsd_intel / cpp2uno.cxx
blobf12abf70ba2aca1bc1fbebf6eccc4fc90db32349
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.5 $
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 <hash_map>
36 #include <sal/alloca.h>
37 #include <rtl/alloc.h>
38 #include <osl/mutex.hxx>
40 #include <uno/data.h>
41 #include <typelib/typedescription.hxx>
43 #include <bridges/cpp_uno/bridge.hxx>
44 #include <bridges/cpp_uno/type_misc.hxx>
46 #include "share.hxx"
49 using namespace ::osl;
50 using namespace ::rtl;
51 using namespace ::com::sun::star::uno;
53 namespace CPPU_CURRENT_NAMESPACE
56 //==================================================================================================
57 rtl_StandardModuleCount g_moduleCount = MODULE_COUNT_INIT;
59 //==================================================================================================
60 static typelib_TypeClass cpp2uno_call(
61 cppu_cppInterfaceProxy * pThis,
62 const typelib_TypeDescription * pMemberTypeDescr,
63 typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return
64 sal_Int32 nParams, typelib_MethodParameter * pParams,
65 void ** pCallStack,
66 sal_Int64 * pRegisterReturn /* space for register return */ )
68 // pCallStack: ret, [return ptr], this, params
69 char * pCppStack = (char *)(pCallStack +1);
71 // return
72 typelib_TypeDescription * pReturnTypeDescr = 0;
73 if (pReturnTypeRef)
74 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
76 void * pUnoReturn = 0;
77 void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
79 if (pReturnTypeDescr)
81 if (cppu_isSimpleType( pReturnTypeDescr ))
83 pUnoReturn = pRegisterReturn; // direct way for simple types
85 else // complex return via ptr (pCppReturn)
87 pCppReturn = *(void **)pCppStack;
88 pCppStack += sizeof(void *);
90 pUnoReturn = (cppu_relatesToInterface( pReturnTypeDescr )
91 ? alloca( pReturnTypeDescr->nSize )
92 : pCppReturn); // direct way
95 // pop this
96 pCppStack += sizeof( void* );
98 // stack space
99 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" );
100 // parameters
101 void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams );
102 void ** pCppArgs = pUnoArgs + nParams;
103 // indizes of values this have to be converted (interface conversion cpp<=>uno)
104 sal_Int32 * pTempIndizes = (sal_Int32 *)(pUnoArgs + (2 * nParams));
105 // type descriptions for reconversions
106 typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams));
108 sal_Int32 nTempIndizes = 0;
110 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
112 const typelib_MethodParameter & rParam = pParams[nPos];
113 typelib_TypeDescription * pParamTypeDescr = 0;
114 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
116 if (!rParam.bOut && cppu_isSimpleType( pParamTypeDescr )) // value
118 pCppArgs[nPos] = pCppStack;
119 pUnoArgs[nPos] = pCppStack;
120 switch (pParamTypeDescr->eTypeClass)
122 case typelib_TypeClass_HYPER:
123 case typelib_TypeClass_UNSIGNED_HYPER:
124 case typelib_TypeClass_DOUBLE:
125 pCppStack += sizeof(sal_Int32); // extra long
127 // no longer needed
128 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
130 else // ptr to complex value | ref
132 pCppArgs[nPos] = *(void **)pCppStack;
134 if (! rParam.bIn) // is pure out
136 // uno out is unconstructed mem!
137 pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
138 pTempIndizes[nTempIndizes] = nPos;
139 // will be released at reconversion
140 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
142 // is in/inout
143 else if (cppu_relatesToInterface( pParamTypeDescr ))
145 uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
146 *(void **)pCppStack, pParamTypeDescr,
147 &pThis->pBridge->aCpp2Uno );
148 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
149 // will be released at reconversion
150 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
152 else // direct way
154 pUnoArgs[nPos] = *(void **)pCppStack;
155 // no longer needed
156 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
159 pCppStack += sizeof(sal_Int32); // standard parameter length
162 // ExceptionHolder
163 uno_Any aUnoExc; // Any will be constructed by callee
164 uno_Any * pUnoExc = &aUnoExc;
166 // invoke uno dispatch call
167 (*pThis->pUnoI->pDispatcher)( pThis->pUnoI, pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
169 // in case an exception occured...
170 if (pUnoExc)
172 // destruct temporary in/inout params
173 for ( ; nTempIndizes--; )
175 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
177 if (pParams[nIndex].bIn) // is in/inout => was constructed
178 uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], 0 );
179 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
181 if (pReturnTypeDescr)
182 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
184 raiseException( &aUnoExc, &pThis->pBridge->aUno2Cpp ); // has to destruct the any
185 // is here for dummy
186 return typelib_TypeClass_VOID;
188 else // else no exception occured...
190 // temporary params
191 for ( ; nTempIndizes--; )
193 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
194 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
196 if (pParams[nIndex].bOut) // inout/out
198 // convert and assign
199 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
200 uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
201 &pThis->pBridge->aUno2Cpp );
203 // destroy temp uno param
204 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
206 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
208 // return
209 if (pCppReturn) // has complex return
211 if (pUnoReturn != pCppReturn) // needs reconversion
213 uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
214 &pThis->pBridge->aUno2Cpp );
215 // destroy temp uno return
216 uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
218 // complex return ptr is set to eax
219 *(void **)pRegisterReturn = pCppReturn;
221 if (pReturnTypeDescr)
223 typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
224 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
225 return eRet;
227 else
228 return typelib_TypeClass_VOID;
233 //==================================================================================================
234 static typelib_TypeClass cpp_mediate(
235 sal_Int32 nVtableCall,
236 void ** pCallStack,
237 sal_Int64 * pRegisterReturn /* space for register return */ )
239 OSL_ENSURE( sizeof(sal_Int32)==sizeof(void *), "### unexpected!" );
241 // pCallStack: ret adr, [ret *], this, params
242 // _this_ ptr is patched cppu_XInterfaceProxy object
243 cppu_cppInterfaceProxy * pCppI = NULL;
244 if( nVtableCall & 0x80000000 )
246 nVtableCall &= 0x7fffffff;
247 pCppI = (cppu_cppInterfaceProxy *)(XInterface *)*(pCallStack +2);
249 else
251 pCppI = (cppu_cppInterfaceProxy *)(XInterface *)*(pCallStack +1);
254 typelib_InterfaceTypeDescription * pTypeDescr = pCppI->pTypeDescr;
256 OSL_ENSURE( nVtableCall < pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!" );
257 if (nVtableCall >= pTypeDescr->nMapFunctionIndexToMemberIndex)
259 throw RuntimeException(
260 OUString::createFromAscii("illegal vtable index!"),
261 (XInterface *)pCppI );
264 // determine called method
265 OSL_ENSURE( nVtableCall < pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!" );
266 sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nVtableCall];
267 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!" );
269 TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
271 typelib_TypeClass eRet;
272 switch (aMemberDescr.get()->eTypeClass)
274 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
276 if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nVtableCall)
278 // is GET method
279 eRet = cpp2uno_call(
280 pCppI, aMemberDescr.get(),
281 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef,
282 0, 0, // no params
283 pCallStack, pRegisterReturn );
285 else
287 // is SET method
288 typelib_MethodParameter aParam;
289 aParam.pTypeRef =
290 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef;
291 aParam.bIn = sal_True;
292 aParam.bOut = sal_False;
294 eRet = cpp2uno_call(
295 pCppI, aMemberDescr.get(),
296 0, // indicates void return
297 1, &aParam,
298 pCallStack, pRegisterReturn );
300 break;
302 case typelib_TypeClass_INTERFACE_METHOD:
304 // is METHOD
305 switch (nVtableCall)
307 case 1: // acquire()
308 pCppI->acquireProxy(); // non virtual call!
309 eRet = typelib_TypeClass_VOID;
310 break;
311 case 2: // release()
312 pCppI->releaseProxy(); // non virtual call!
313 eRet = typelib_TypeClass_VOID;
314 break;
315 case 0: // queryInterface() opt
317 typelib_TypeDescription * pTD = 0;
318 TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pCallStack[3] )->getTypeLibType() );
319 if (pTD)
321 XInterface * pInterface = 0;
322 (*pCppI->pBridge->pCppEnv->getRegisteredInterface)(
323 pCppI->pBridge->pCppEnv,
324 (void **)&pInterface, pCppI->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
326 if (pInterface)
328 ::uno_any_construct(
329 reinterpret_cast< uno_Any * >( pCallStack[1] ),
330 &pInterface, pTD, cpp_acquire );
331 pInterface->release();
332 TYPELIB_DANGER_RELEASE( pTD );
333 *(void **)pRegisterReturn = pCallStack[1];
334 eRet = typelib_TypeClass_ANY;
335 break;
337 TYPELIB_DANGER_RELEASE( pTD );
339 } // else perform queryInterface()
340 default:
341 eRet = cpp2uno_call(
342 pCppI, aMemberDescr.get(),
343 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef,
344 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams,
345 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams,
346 pCallStack, pRegisterReturn );
348 break;
350 default:
352 throw RuntimeException(
353 OUString::createFromAscii("no member description found!"),
354 (XInterface *)pCppI );
355 // is here for dummy
356 eRet = typelib_TypeClass_VOID;
360 return eRet;
363 //==================================================================================================
365 * is called on incoming vtable calls
366 * (called by asm snippets)
368 static void cpp_vtable_call( int nTableEntry, void** pCallStack ) __attribute__((regparm(2)));
370 void cpp_vtable_call( int nTableEntry, void** pCallStack )
372 volatile long nRegReturn[2];
373 typelib_TypeClass aType = cpp_mediate( nTableEntry, pCallStack, (sal_Int64*)nRegReturn );
375 switch( aType )
377 case typelib_TypeClass_HYPER:
378 case typelib_TypeClass_UNSIGNED_HYPER:
379 __asm__( "movl %1, %%edx\n\t"
380 "movl %0, %%eax\n"
381 : : "m"(nRegReturn[0]), "m"(nRegReturn[1]) );
382 break;
383 case typelib_TypeClass_FLOAT:
384 __asm__( "flds %0\n\t"
385 "fstp %%st(0)\n\t"
386 "flds %0\n"
387 : : "m"(*(float *)nRegReturn) );
388 break;
389 case typelib_TypeClass_DOUBLE:
390 __asm__( "fldl %0\n\t"
391 "fstp %%st(0)\n\t"
392 "fldl %0\n"
393 : : "m"(*(double *)nRegReturn) );
394 break;
395 // case typelib_TypeClass_UNSIGNED_SHORT:
396 // case typelib_TypeClass_SHORT:
397 // __asm__( "movswl %0, %%eax\n"
398 // : : "m"(nRegReturn) );
399 // break;
400 default:
401 __asm__( "movl %0, %%eax\n"
402 : : "m"(nRegReturn[0]) );
403 break;
408 //==================================================================================================
409 class MediateClassData
411 typedef ::std::hash_map< OUString, void *, OUStringHash > t_classdata_map;
412 t_classdata_map m_map;
413 Mutex m_mutex;
415 public:
416 void const * get_vtable( typelib_InterfaceTypeDescription * pTD ) SAL_THROW( () );
418 inline MediateClassData() SAL_THROW( () )
420 ~MediateClassData() SAL_THROW( () );
422 //__________________________________________________________________________________________________
423 MediateClassData::~MediateClassData() SAL_THROW( () )
425 OSL_TRACE( "> calling ~MediateClassData(): freeing mediate vtables." );
427 for ( t_classdata_map::const_iterator iPos( m_map.begin() ); iPos != m_map.end(); ++iPos )
429 ::rtl_freeMemory( iPos->second );
432 //--------------------------------------------------------------------------------------------------
433 static inline void codeSnippet( char * code, sal_uInt32 vtable_pos, bool simple_ret_type ) SAL_THROW( () )
435 if (! simple_ret_type)
436 vtable_pos |= 0x80000000;
437 OSL_ASSERT( sizeof (long) == 4 );
438 // mov $nPos, %eax
439 *code++ = 0xb8;
440 *(long *)code = vtable_pos;
441 code += sizeof (long);
442 // mov %esp, %edx
443 *code++ = 0x89;
444 *code++ = 0xe2;
445 // jmp cpp_vtable_call
446 *code++ = 0xe9;
447 *(long *)code = ((char *)cpp_vtable_call) - code - sizeof (long);
449 //__________________________________________________________________________________________________
450 void const * MediateClassData::get_vtable( typelib_InterfaceTypeDescription * pTD ) SAL_THROW( () )
452 void * buffer;
454 // avoiding locked counts
455 OUString const & unoName = *(OUString const *)&((typelib_TypeDescription *)pTD)->pTypeName;
457 MutexGuard aGuard( m_mutex );
458 t_classdata_map::const_iterator iFind( m_map.find( unoName ) );
459 if (iFind == m_map.end())
461 // create new vtable
462 sal_Int32 nSlots = pTD->nMapFunctionIndexToMemberIndex;
463 buffer = ::rtl_allocateMemory( ((2+ nSlots) * sizeof (void *)) + (nSlots *20) );
465 ::std::pair< t_classdata_map::iterator, bool > insertion(
466 m_map.insert( t_classdata_map::value_type( unoName, buffer ) ) );
467 OSL_ENSURE( insertion.second, "### inserting new vtable buffer failed?!" );
469 void ** slots = (void **)buffer;
470 *slots++ = 0;
471 *slots++ = 0; // rtti
472 char * code = (char *)(slots + nSlots);
474 sal_uInt32 vtable_pos = 0;
475 sal_Int32 nAllMembers = pTD->nAllMembers;
476 typelib_TypeDescriptionReference ** ppAllMembers = pTD->ppAllMembers;
477 for ( sal_Int32 nPos = 0; nPos < nAllMembers; ++nPos )
479 typelib_TypeDescription * pTD = 0;
480 TYPELIB_DANGER_GET( &pTD, ppAllMembers[ nPos ] );
481 OSL_ASSERT( pTD );
482 if (typelib_TypeClass_INTERFACE_ATTRIBUTE == pTD->eTypeClass)
484 bool simple_ret = cppu_isSimpleType(
485 ((typelib_InterfaceAttributeTypeDescription *)pTD)->pAttributeTypeRef->eTypeClass );
486 // get method
487 *slots++ = code;
488 codeSnippet( code, vtable_pos++, simple_ret );
489 code += 20;
490 if (! ((typelib_InterfaceAttributeTypeDescription *)pTD)->bReadOnly)
492 // set method
493 *slots++ = code;
494 codeSnippet( code, vtable_pos++, true );
495 code += 20;
498 else
500 bool simple_ret = cppu_isSimpleType(
501 ((typelib_InterfaceMethodTypeDescription *)pTD)->pReturnTypeRef->eTypeClass );
502 *slots++ = code;
503 codeSnippet( code, vtable_pos++, simple_ret );
504 code += 20;
506 TYPELIB_DANGER_RELEASE( pTD );
508 OSL_ASSERT( vtable_pos == nSlots );
510 else
512 buffer = iFind->second;
516 return ((void **)buffer +2);
519 //==================================================================================================
520 void SAL_CALL cppu_cppInterfaceProxy_patchVtable(
521 XInterface * pCppI, typelib_InterfaceTypeDescription * pTypeDescr ) throw ()
523 static MediateClassData * s_pMediateClassData = 0;
524 if (! s_pMediateClassData)
526 MutexGuard aGuard( Mutex::getGlobalMutex() );
527 if (! s_pMediateClassData)
529 #ifdef LEAK_STATIC_DATA
530 s_pMediateClassData = new MediateClassData();
531 #else
532 static MediateClassData s_aMediateClassData;
533 s_pMediateClassData = &s_aMediateClassData;
534 #endif
537 *(void const **)pCppI = s_pMediateClassData->get_vtable( pTypeDescr );
542 extern "C"
544 //##################################################################################################
545 sal_Bool SAL_CALL component_canUnload( TimeValue * pTime )
546 SAL_THROW_EXTERN_C()
548 return CPPU_CURRENT_NAMESPACE::g_moduleCount.canUnload(
549 &CPPU_CURRENT_NAMESPACE::g_moduleCount, pTime );
551 //##################################################################################################
552 void SAL_CALL uno_initEnvironment( uno_Environment * pCppEnv )
553 SAL_THROW_EXTERN_C()
555 CPPU_CURRENT_NAMESPACE::cppu_cppenv_initEnvironment(
556 pCppEnv );
558 //##################################################################################################
559 void SAL_CALL uno_ext_getMapping(
560 uno_Mapping ** ppMapping, uno_Environment * pFrom, uno_Environment * pTo )
561 SAL_THROW_EXTERN_C()
563 CPPU_CURRENT_NAMESPACE::cppu_ext_getMapping(
564 ppMapping, pFrom, pTo );