1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: cpp2uno.cxx,v $
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 <sal/alloca.h>
36 #include <com/sun/star/uno/genfunc.hxx>
37 #include "com/sun/star/uno/RuntimeException.hpp"
39 #include <typelib/typedescription.hxx>
41 #include "bridges/cpp_uno/shared/bridge.hxx"
42 #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx"
43 #include "bridges/cpp_uno/shared/types.hxx"
44 #include "bridges/cpp_uno/shared/vtablefactory.hxx"
48 using namespace ::com::sun::star::uno
;
53 //==================================================================================================
54 static typelib_TypeClass
cpp2uno_call(
55 bridges::cpp_uno::shared::CppInterfaceProxy
* pThis
,
56 const typelib_TypeDescription
* pMemberTypeDescr
,
57 typelib_TypeDescriptionReference
* pReturnTypeRef
, // 0 indicates void return
58 sal_Int32 nParams
, typelib_MethodParameter
* pParams
,
60 sal_Int64
* pRegisterReturn
/* space for register return */ )
62 // pCallStack: ret, [return ptr], this, params
63 char * pCppStack
= (char *)(pCallStack
+1);
66 typelib_TypeDescription
* pReturnTypeDescr
= 0;
68 TYPELIB_DANGER_GET( &pReturnTypeDescr
, pReturnTypeRef
);
70 void * pUnoReturn
= 0;
71 void * pCppReturn
= 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
75 if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr
))
77 pUnoReturn
= pRegisterReturn
; // direct way for simple types
79 else // complex return via ptr (pCppReturn)
81 pCppReturn
= *(void **)pCppStack
;
82 pCppStack
+= sizeof(void *);
84 pUnoReturn
= (bridges::cpp_uno::shared::relatesToInterfaceType(
86 ? alloca( pReturnTypeDescr
->nSize
)
87 : pCppReturn
); // direct way
91 pCppStack
+= sizeof( void* );
94 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32
), "### unexpected size!" );
96 void ** pUnoArgs
= (void **)alloca( 4 * sizeof(void *) * nParams
);
97 void ** pCppArgs
= pUnoArgs
+ nParams
;
98 // indizes of values this have to be converted (interface conversion cpp<=>uno)
99 sal_Int32
* pTempIndizes
= (sal_Int32
*)(pUnoArgs
+ (2 * nParams
));
100 // type descriptions for reconversions
101 typelib_TypeDescription
** ppTempParamTypeDescr
= (typelib_TypeDescription
**)(pUnoArgs
+ (3 * nParams
));
103 sal_Int32 nTempIndizes
= 0;
105 for ( sal_Int32 nPos
= 0; nPos
< nParams
; ++nPos
)
107 const typelib_MethodParameter
& rParam
= pParams
[nPos
];
108 typelib_TypeDescription
* pParamTypeDescr
= 0;
109 TYPELIB_DANGER_GET( &pParamTypeDescr
, rParam
.pTypeRef
);
112 && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr
))
115 pCppArgs
[nPos
] = pCppStack
;
116 pUnoArgs
[nPos
] = pCppStack
;
117 switch (pParamTypeDescr
->eTypeClass
)
119 case typelib_TypeClass_HYPER
:
120 case typelib_TypeClass_UNSIGNED_HYPER
:
121 case typelib_TypeClass_DOUBLE
:
122 pCppStack
+= sizeof(sal_Int32
); // extra long
125 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
127 else // ptr to complex value | ref
129 pCppArgs
[nPos
] = *(void **)pCppStack
;
131 if (! rParam
.bIn
) // is pure out
133 // uno out is unconstructed mem!
134 pUnoArgs
[nPos
] = alloca( pParamTypeDescr
->nSize
);
135 pTempIndizes
[nTempIndizes
] = nPos
;
136 // will be released at reconversion
137 ppTempParamTypeDescr
[nTempIndizes
++] = pParamTypeDescr
;
140 else if (bridges::cpp_uno::shared::relatesToInterfaceType(
143 uno_copyAndConvertData( pUnoArgs
[nPos
] = alloca( pParamTypeDescr
->nSize
),
144 *(void **)pCppStack
, pParamTypeDescr
,
145 pThis
->getBridge()->getCpp2Uno() );
146 pTempIndizes
[nTempIndizes
] = nPos
; // has to be reconverted
147 // will be released at reconversion
148 ppTempParamTypeDescr
[nTempIndizes
++] = pParamTypeDescr
;
152 pUnoArgs
[nPos
] = *(void **)pCppStack
;
154 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
157 pCppStack
+= sizeof(sal_Int32
); // standard parameter length
161 uno_Any aUnoExc
; // Any will be constructed by callee
162 uno_Any
* pUnoExc
= &aUnoExc
;
164 // invoke uno dispatch call
165 (*pThis
->getUnoI()->pDispatcher
)(
166 pThis
->getUnoI(), pMemberTypeDescr
, pUnoReturn
, pUnoArgs
, &pUnoExc
);
168 // in case an exception occured...
171 // destruct temporary in/inout params
172 for ( ; nTempIndizes
--; )
174 sal_Int32 nIndex
= pTempIndizes
[nTempIndizes
];
176 if (pParams
[nIndex
].bIn
) // is in/inout => was constructed
177 uno_destructData( pUnoArgs
[nIndex
], ppTempParamTypeDescr
[nTempIndizes
], 0 );
178 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr
[nTempIndizes
] );
180 if (pReturnTypeDescr
)
181 TYPELIB_DANGER_RELEASE( pReturnTypeDescr
);
183 CPPU_CURRENT_NAMESPACE::raiseException(
184 &aUnoExc
, pThis
->getBridge()->getUno2Cpp() );
185 // has to destruct the any
187 return typelib_TypeClass_VOID
;
189 else // else no exception occured...
192 for ( ; nTempIndizes
--; )
194 sal_Int32 nIndex
= pTempIndizes
[nTempIndizes
];
195 typelib_TypeDescription
* pParamTypeDescr
= ppTempParamTypeDescr
[nTempIndizes
];
197 if (pParams
[nIndex
].bOut
) // inout/out
199 // convert and assign
200 uno_destructData( pCppArgs
[nIndex
], pParamTypeDescr
, cpp_release
);
201 uno_copyAndConvertData( pCppArgs
[nIndex
], pUnoArgs
[nIndex
], pParamTypeDescr
,
202 pThis
->getBridge()->getUno2Cpp() );
204 // destroy temp uno param
205 uno_destructData( pUnoArgs
[nIndex
], pParamTypeDescr
, 0 );
207 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
210 if (pCppReturn
) // has complex return
212 if (pUnoReturn
!= pCppReturn
) // needs reconversion
214 uno_copyAndConvertData( pCppReturn
, pUnoReturn
, pReturnTypeDescr
,
215 pThis
->getBridge()->getUno2Cpp() );
216 // destroy temp uno return
217 uno_destructData( pUnoReturn
, pReturnTypeDescr
, 0 );
219 // complex return ptr is set to eax
220 *(void **)pRegisterReturn
= pCppReturn
;
222 if (pReturnTypeDescr
)
224 typelib_TypeClass eRet
= (typelib_TypeClass
)pReturnTypeDescr
->eTypeClass
;
225 TYPELIB_DANGER_RELEASE( pReturnTypeDescr
);
229 return typelib_TypeClass_VOID
;
234 //==================================================================================================
235 static typelib_TypeClass
cpp_mediate(
236 sal_Int32 nFunctionIndex
,
237 sal_Int32 nVtableOffset
,
239 sal_Int64
* pRegisterReturn
/* space for register return */ )
241 OSL_ENSURE( sizeof(sal_Int32
)==sizeof(void *), "### unexpected!" );
243 // pCallStack: ret adr, [ret *], this, params
245 if( nFunctionIndex
& 0x80000000 )
247 nFunctionIndex
&= 0x7fffffff;
248 pThis
= pCallStack
[2];
252 pThis
= pCallStack
[1];
254 pThis
= static_cast< char * >(pThis
) - nVtableOffset
;
255 bridges::cpp_uno::shared::CppInterfaceProxy
* pCppI
256 = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
259 typelib_InterfaceTypeDescription
* pTypeDescr
= pCppI
->getTypeDescr();
261 OSL_ENSURE( nFunctionIndex
< pTypeDescr
->nMapFunctionIndexToMemberIndex
, "### illegal vtable index!" );
262 if (nFunctionIndex
>= pTypeDescr
->nMapFunctionIndexToMemberIndex
)
264 throw RuntimeException(
265 rtl::OUString::createFromAscii("illegal vtable index!"),
266 (XInterface
*)pThis
);
269 // determine called method
270 sal_Int32 nMemberPos
= pTypeDescr
->pMapFunctionIndexToMemberIndex
[nFunctionIndex
];
271 OSL_ENSURE( nMemberPos
< pTypeDescr
->nAllMembers
, "### illegal member index!" );
273 TypeDescription
aMemberDescr( pTypeDescr
->ppAllMembers
[nMemberPos
] );
275 typelib_TypeClass eRet
;
276 switch (aMemberDescr
.get()->eTypeClass
)
278 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
280 if (pTypeDescr
->pMapMemberIndexToFunctionIndex
[nMemberPos
] == nFunctionIndex
)
284 pCppI
, aMemberDescr
.get(),
285 ((typelib_InterfaceAttributeTypeDescription
*)aMemberDescr
.get())->pAttributeTypeRef
,
287 pCallStack
, pRegisterReturn
);
292 typelib_MethodParameter aParam
;
294 ((typelib_InterfaceAttributeTypeDescription
*)aMemberDescr
.get())->pAttributeTypeRef
;
295 aParam
.bIn
= sal_True
;
296 aParam
.bOut
= sal_False
;
299 pCppI
, aMemberDescr
.get(),
300 0, // indicates void return
302 pCallStack
, pRegisterReturn
);
306 case typelib_TypeClass_INTERFACE_METHOD
:
309 switch (nFunctionIndex
)
312 pCppI
->acquireProxy(); // non virtual call!
313 eRet
= typelib_TypeClass_VOID
;
316 pCppI
->releaseProxy(); // non virtual call!
317 eRet
= typelib_TypeClass_VOID
;
319 case 0: // queryInterface() opt
321 typelib_TypeDescription
* pTD
= 0;
322 TYPELIB_DANGER_GET( &pTD
, reinterpret_cast< Type
* >( pCallStack
[3] )->getTypeLibType() );
325 XInterface
* pInterface
= 0;
326 (*pCppI
->getBridge()->getCppEnv()->getRegisteredInterface
)(
327 pCppI
->getBridge()->getCppEnv(),
328 (void **)&pInterface
, pCppI
->getOid().pData
,
329 (typelib_InterfaceTypeDescription
*)pTD
);
334 reinterpret_cast< uno_Any
* >( pCallStack
[1] ),
335 &pInterface
, pTD
, cpp_acquire
);
336 pInterface
->release();
337 TYPELIB_DANGER_RELEASE( pTD
);
338 *(void **)pRegisterReturn
= pCallStack
[1];
339 eRet
= typelib_TypeClass_ANY
;
342 TYPELIB_DANGER_RELEASE( pTD
);
344 } // else perform queryInterface()
347 pCppI
, aMemberDescr
.get(),
348 ((typelib_InterfaceMethodTypeDescription
*)aMemberDescr
.get())->pReturnTypeRef
,
349 ((typelib_InterfaceMethodTypeDescription
*)aMemberDescr
.get())->nParams
,
350 ((typelib_InterfaceMethodTypeDescription
*)aMemberDescr
.get())->pParams
,
351 pCallStack
, pRegisterReturn
);
357 throw RuntimeException(
358 rtl::OUString::createFromAscii("no member description found!"),
359 (XInterface
*)pThis
);
361 eRet
= typelib_TypeClass_VOID
;
368 //==================================================================================================
370 * is called on incoming vtable calls
371 * (called by asm snippets)
373 static void cpp_vtable_call(
374 int nFunctionIndex
, int nVtableOffset
, void** pCallStack
)
375 __attribute__((regparm(3)));
377 void cpp_vtable_call( int nFunctionIndex
, int nVtableOffset
, void** pCallStack
)
379 volatile long nRegReturn
[2];
380 typelib_TypeClass aType
= cpp_mediate(
381 nFunctionIndex
, nVtableOffset
, pCallStack
, (sal_Int64
*)nRegReturn
);
385 case typelib_TypeClass_HYPER
:
386 case typelib_TypeClass_UNSIGNED_HYPER
:
387 __asm__( "movl %1, %%edx\n\t"
389 : : "m"(nRegReturn
[0]), "m"(nRegReturn
[1]) );
391 case typelib_TypeClass_FLOAT
:
392 __asm__( "flds %0\n\t"
395 : : "m"(*(float *)nRegReturn
) );
397 case typelib_TypeClass_DOUBLE
:
398 __asm__( "fldl %0\n\t"
401 : : "m"(*(double *)nRegReturn
) );
403 // case typelib_TypeClass_UNSIGNED_SHORT:
404 // case typelib_TypeClass_SHORT:
405 // __asm__( "movswl %0, %%eax\n"
406 // : : "m"(nRegReturn) );
409 __asm__( "movl %0, %%eax\n"
410 : : "m"(nRegReturn
[0]) );
416 //==================================================================================================
417 int const codeSnippetSize
= 20;
419 unsigned char * codeSnippet(
420 unsigned char * code
, sal_Int32 functionIndex
, sal_Int32 vtableOffset
,
423 if (!simpleRetType
) {
424 functionIndex
|= 0x80000000;
426 unsigned char * p
= code
;
427 OSL_ASSERT(sizeof (sal_Int32
) == 4);
428 // mov function_index, %eax:
430 *reinterpret_cast< sal_Int32
* >(p
) = functionIndex
;
431 p
+= sizeof (sal_Int32
);
432 // mov vtable_offset, %edx:
434 *reinterpret_cast< sal_Int32
* >(p
) = vtableOffset
;
435 p
+= sizeof (sal_Int32
);
439 // jmp cpp_vtable_call:
441 *reinterpret_cast< sal_Int32
* >(p
)
442 = ((unsigned char *) cpp_vtable_call
) - p
- sizeof (sal_Int32
);
443 p
+= sizeof (sal_Int32
);
444 OSL_ASSERT(p
- code
<= codeSnippetSize
);
445 return code
+ codeSnippetSize
;
450 struct bridges::cpp_uno::shared::VtableFactory::Slot
{ void * fn
; };
452 bridges::cpp_uno::shared::VtableFactory::Slot
*
453 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block
)
455 return static_cast< Slot
* >(block
) + 2;
458 sal_Size
bridges::cpp_uno::shared::VtableFactory::getBlockSize(
461 return (slotCount
+ 2) * sizeof (Slot
) + slotCount
* codeSnippetSize
;
464 bridges::cpp_uno::shared::VtableFactory::Slot
*
465 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
466 void * block
, sal_Int32 slotCount
)
468 Slot
* slots
= mapBlockToVtable(block
);
471 return slots
+ slotCount
;
474 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
475 Slot
** slots
, unsigned char * code
,
476 typelib_InterfaceTypeDescription
const * type
, sal_Int32 functionOffset
,
477 sal_Int32 functionCount
, sal_Int32 vtableOffset
)
479 (*slots
) -= functionCount
;
481 for (sal_Int32 i
= 0; i
< type
->nMembers
; ++i
) {
482 typelib_TypeDescription
* member
= 0;
483 TYPELIB_DANGER_GET(&member
, type
->ppMembers
[i
]);
484 OSL_ASSERT(member
!= 0);
485 switch (member
->eTypeClass
) {
486 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
490 code
, functionOffset
++, vtableOffset
,
491 bridges::cpp_uno::shared::isSimpleType(
493 typelib_InterfaceAttributeTypeDescription
* >(
494 member
)->pAttributeTypeRef
));
496 if (!reinterpret_cast<
497 typelib_InterfaceAttributeTypeDescription
* >(
501 code
= codeSnippet(code
, functionOffset
++, vtableOffset
, true);
505 case typelib_TypeClass_INTERFACE_METHOD
:
508 code
, functionOffset
++, vtableOffset
,
509 bridges::cpp_uno::shared::isSimpleType(
511 typelib_InterfaceMethodTypeDescription
* >(
512 member
)->pReturnTypeRef
));
519 TYPELIB_DANGER_RELEASE(member
);
524 void bridges::cpp_uno::shared::VtableFactory::flushCode(
525 unsigned char const *, unsigned char const *)