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 ************************************************************************/
34 #include <rtl/alloc.h>
35 #include <osl/mutex.hxx>
37 #include <com/sun/star/uno/genfunc.hxx>
38 #include "com/sun/star/uno/RuntimeException.hpp"
40 #include <typelib/typedescription.hxx>
42 #include "bridges/cpp_uno/shared/bridge.hxx"
43 #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx"
44 #include "bridges/cpp_uno/shared/types.hxx"
45 #include "bridges/cpp_uno/shared/vtablefactory.hxx"
52 using namespace ::osl
;
53 using namespace ::rtl
;
54 using namespace ::com::sun::star::uno
;
59 static typelib_TypeClass
cpp2uno_call(
60 bridges::cpp_uno::shared::CppInterfaceProxy
* pThis
,
61 const typelib_TypeDescription
* pMemberTypeDescr
,
62 typelib_TypeDescriptionReference
* pReturnTypeRef
,
63 sal_Int32 nParams
, typelib_MethodParameter
* pParams
,
65 sal_Int64
* pRegisterReturn
/* space for register return */ )
67 // pCallStack: ret, [return ptr], this, params
68 char * pTopStack
= (char *)(pCallStack
+ 0);
69 char * pCppStack
= pTopStack
;
72 typelib_TypeDescription
* pReturnTypeDescr
= 0;
74 TYPELIB_DANGER_GET( &pReturnTypeDescr
, pReturnTypeRef
);
76 void * pUnoReturn
= 0;
77 // complex return ptr: if != 0 && != pUnoReturn, reconversion need
78 void * pCppReturn
= 0;
82 if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr
))
84 pUnoReturn
= pRegisterReturn
; // direct way for simple types
86 else // complex return via ptr (pCppReturn)
88 pCppReturn
= *(void **)pCppStack
;
89 pCppStack
+= sizeof(void *);
91 pUnoReturn
= (bridges::cpp_uno::shared::relatesToInterfaceType(
93 ? alloca( pReturnTypeDescr
->nSize
)
94 : pCppReturn
); // direct way
98 pCppStack
+= sizeof( void* );
101 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32
),
102 "### unexpected size!" );
104 void ** pUnoArgs
= (void **)alloca( 4 * sizeof(void *) * nParams
);
105 void ** pCppArgs
= pUnoArgs
+ nParams
;
106 // indizes of values this have to be converted (interface conversion
108 sal_Int32
* pTempIndizes
= (sal_Int32
*)(pUnoArgs
+ (2 * nParams
));
109 // type descriptions for reconversions
110 typelib_TypeDescription
** ppTempParamTypeDescr
=
111 (typelib_TypeDescription
**)(pUnoArgs
+ (3 * nParams
));
113 sal_Int32 nTempIndizes
= 0;
115 for ( sal_Int32 nPos
= 0; nPos
< nParams
; ++nPos
)
117 const typelib_MethodParameter
& rParam
= pParams
[nPos
];
118 typelib_TypeDescription
* pParamTypeDescr
= 0;
119 TYPELIB_DANGER_GET( &pParamTypeDescr
, rParam
.pTypeRef
);
122 bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr
))
125 switch (pParamTypeDescr
->eTypeClass
)
127 case typelib_TypeClass_HYPER
:
128 case typelib_TypeClass_UNSIGNED_HYPER
:
129 case typelib_TypeClass_DOUBLE
:
130 if ((pCppStack
- pTopStack
) % 8) pCppStack
+=sizeof(sal_Int32
); //align to 8
137 pCppArgs
[nPos
] = pCppStack
;
138 pUnoArgs
[nPos
] = pCppStack
;
139 switch (pParamTypeDescr
->eTypeClass
)
141 case typelib_TypeClass_HYPER
:
142 case typelib_TypeClass_UNSIGNED_HYPER
:
143 case typelib_TypeClass_DOUBLE
:
144 pCppStack
+= sizeof(sal_Int32
); // extra long
150 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
152 else // ptr to complex value | ref
154 pCppArgs
[nPos
] = *(void **)pCppStack
;
156 if (! rParam
.bIn
) // is pure out
158 // uno out is unconstructed mem!
159 pUnoArgs
[nPos
] = alloca( pParamTypeDescr
->nSize
);
160 pTempIndizes
[nTempIndizes
] = nPos
;
161 // will be released at reconversion
162 ppTempParamTypeDescr
[nTempIndizes
++] = pParamTypeDescr
;
165 else if (bridges::cpp_uno::shared::relatesToInterfaceType(
168 uno_copyAndConvertData( pUnoArgs
[nPos
] =
169 alloca( pParamTypeDescr
->nSize
),
170 *(void **)pCppStack
, pParamTypeDescr
,
171 pThis
->getBridge()->getCpp2Uno() );
172 pTempIndizes
[nTempIndizes
] = nPos
; // has to be reconverted
173 // will be released at reconversion
174 ppTempParamTypeDescr
[nTempIndizes
++] = pParamTypeDescr
;
178 pUnoArgs
[nPos
] = *(void **)pCppStack
;
180 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
183 pCppStack
+= sizeof(sal_Int32
); // standard parameter length
187 uno_Any aUnoExc
; // Any will be constructed by callee
188 uno_Any
* pUnoExc
= &aUnoExc
;
190 // invoke uno dispatch call
191 (*pThis
->getUnoI()->pDispatcher
)(
192 pThis
->getUnoI(), pMemberTypeDescr
, pUnoReturn
, pUnoArgs
, &pUnoExc
);
194 // in case an exception occured...
197 // destruct temporary in/inout params
198 for ( ; nTempIndizes
--; )
200 sal_Int32 nIndex
= pTempIndizes
[nTempIndizes
];
202 if (pParams
[nIndex
].bIn
) // is in/inout => was constructed
203 uno_destructData( pUnoArgs
[nIndex
],
204 ppTempParamTypeDescr
[nTempIndizes
], 0 );
205 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr
[nTempIndizes
] );
207 if (pReturnTypeDescr
)
208 TYPELIB_DANGER_RELEASE( pReturnTypeDescr
);
210 CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc
,
211 pThis
->getBridge()->getUno2Cpp() ); // has to destruct the any
213 return typelib_TypeClass_VOID
;
215 else // else no exception occured...
218 for ( ; nTempIndizes
--; )
220 sal_Int32 nIndex
= pTempIndizes
[nTempIndizes
];
221 typelib_TypeDescription
* pParamTypeDescr
=
222 ppTempParamTypeDescr
[nTempIndizes
];
224 if (pParams
[nIndex
].bOut
) // inout/out
226 // convert and assign
227 uno_destructData( pCppArgs
[nIndex
], pParamTypeDescr
,
229 uno_copyAndConvertData( pCppArgs
[nIndex
], pUnoArgs
[nIndex
],
230 pParamTypeDescr
, pThis
->getBridge()->getUno2Cpp() );
232 // destroy temp uno param
233 uno_destructData( pUnoArgs
[nIndex
], pParamTypeDescr
, 0 );
235 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
238 if (pCppReturn
) // has complex return
240 if (pUnoReturn
!= pCppReturn
) // needs reconversion
242 uno_copyAndConvertData( pCppReturn
, pUnoReturn
,
243 pReturnTypeDescr
, pThis
->getBridge()->getUno2Cpp() );
244 // destroy temp uno return
245 uno_destructData( pUnoReturn
, pReturnTypeDescr
, 0 );
247 // complex return ptr is set to eax
248 *(void **)pRegisterReturn
= pCppReturn
;
250 if (pReturnTypeDescr
)
252 typelib_TypeClass eRet
=
253 (typelib_TypeClass
)pReturnTypeDescr
->eTypeClass
;
254 TYPELIB_DANGER_RELEASE( pReturnTypeDescr
);
258 return typelib_TypeClass_VOID
;
263 //=====================================================================
264 static typelib_TypeClass
cpp_mediate(
265 sal_Int32 nFunctionIndex
, sal_Int32 nVtableOffset
,
267 sal_Int64
* pRegisterReturn
/* space for register return */ )
269 OSL_ENSURE( sizeof(sal_Int32
)==sizeof(void *), "### unexpected!" );
271 // pCallStack: [ret *], this, params
272 // _this_ ptr is patched cppu_XInterfaceProxy object
274 if( nFunctionIndex
& 0x80000000 )
276 nFunctionIndex
&= 0x7fffffff;
277 pThis
= pCallStack
[1];
281 pThis
= pCallStack
[0];
284 pThis
= static_cast< char * >(pThis
) - nVtableOffset
;
285 bridges::cpp_uno::shared::CppInterfaceProxy
* pCppI
=
286 bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
289 typelib_InterfaceTypeDescription
* pTypeDescr
= pCppI
->getTypeDescr();
291 OSL_ENSURE( nFunctionIndex
< pTypeDescr
->nMapFunctionIndexToMemberIndex
,
292 "### illegal vtable index!" );
293 if (nFunctionIndex
>= pTypeDescr
->nMapFunctionIndexToMemberIndex
)
295 throw RuntimeException(
296 OUString::createFromAscii("illegal vtable index!"),
297 (XInterface
*)pCppI
);
300 // determine called method
301 OSL_ENSURE( nFunctionIndex
< pTypeDescr
->nMapFunctionIndexToMemberIndex
,
302 "### illegal vtable index!" );
303 sal_Int32 nMemberPos
=
304 pTypeDescr
->pMapFunctionIndexToMemberIndex
[nFunctionIndex
];
305 OSL_ENSURE( nMemberPos
< pTypeDescr
->nAllMembers
,
306 "### illegal member index!" );
308 TypeDescription
aMemberDescr( pTypeDescr
->ppAllMembers
[nMemberPos
] );
310 typelib_TypeClass eRet
;
311 switch (aMemberDescr
.get()->eTypeClass
)
313 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
315 if (pTypeDescr
->pMapMemberIndexToFunctionIndex
[nMemberPos
] ==
320 pCppI
, aMemberDescr
.get(),
321 ((typelib_InterfaceAttributeTypeDescription
*)aMemberDescr
.get())->pAttributeTypeRef
,
323 pCallStack
, pRegisterReturn
);
328 typelib_MethodParameter aParam
;
330 ((typelib_InterfaceAttributeTypeDescription
*)aMemberDescr
.get())->pAttributeTypeRef
;
331 aParam
.bIn
= sal_True
;
332 aParam
.bOut
= sal_False
;
335 pCppI
, aMemberDescr
.get(),
336 0, // indicates void return
338 pCallStack
, pRegisterReturn
);
342 case typelib_TypeClass_INTERFACE_METHOD
:
345 switch (nFunctionIndex
)
348 pCppI
->acquireProxy(); // non virtual call!
349 eRet
= typelib_TypeClass_VOID
;
352 pCppI
->releaseProxy(); // non virtual call!
353 eRet
= typelib_TypeClass_VOID
;
355 case 0: // queryInterface() opt
357 typelib_TypeDescription
* pTD
= 0;
358 TYPELIB_DANGER_GET(&pTD
,
359 reinterpret_cast<Type
*>(pCallStack
[2])->getTypeLibType());
362 XInterface
* pInterface
= 0;
363 (*pCppI
->getBridge()->getCppEnv()->getRegisteredInterface
)(
364 pCppI
->getBridge()->getCppEnv(),
365 (void **)&pInterface
, pCppI
->getOid().pData
,
366 (typelib_InterfaceTypeDescription
*)pTD
);
371 reinterpret_cast< uno_Any
* >( pCallStack
[0] ),
372 &pInterface
, pTD
, cpp_acquire
);
373 pInterface
->release();
374 TYPELIB_DANGER_RELEASE( pTD
);
375 *(void **)pRegisterReturn
= pCallStack
[0];
376 eRet
= typelib_TypeClass_ANY
;
379 TYPELIB_DANGER_RELEASE( pTD
);
381 } // else perform queryInterface()
384 pCppI
, aMemberDescr
.get(),
385 ((typelib_InterfaceMethodTypeDescription
*)aMemberDescr
.get())->pReturnTypeRef
,
386 ((typelib_InterfaceMethodTypeDescription
*)aMemberDescr
.get())->nParams
,
387 ((typelib_InterfaceMethodTypeDescription
*)aMemberDescr
.get())->pParams
,
388 pCallStack
, pRegisterReturn
);
394 throw RuntimeException(
395 OUString::createFromAscii("no member description found!"),
396 (XInterface
*)pCppI
);
398 eRet
= typelib_TypeClass_VOID
;
406 //=======================================================================
408 * is called on incoming vtable calls
409 * (called by asm snippets)
412 extern "C" sal_Int64
cpp_vtable_call( long *pFunctionAndOffset
,
415 sal_Int64 nRegReturn
;
416 cpp_mediate( pFunctionAndOffset
[0], pFunctionAndOffset
[1], pCallStack
,
421 extern "C" void privateSnippetExecutor(void);
425 const int codeSnippetSize
= 20;
427 unsigned char *codeSnippet(unsigned char* code
, sal_Int32 functionIndex
,
428 sal_Int32 vtableOffset
, bool simple_ret_type
)
430 if (!simple_ret_type
)
431 functionIndex
|= 0x80000000;
433 unsigned long * p
= (unsigned long *)code
;
437 *p
++ = (unsigned long)functionIndex
;
438 *p
++ = (unsigned long)vtableOffset
;
439 *p
++ = (unsigned long)privateSnippetExecutor
;
441 return code
+ codeSnippetSize
;
445 struct bridges::cpp_uno::shared::VtableFactory::Slot
{ void * fn
; };
447 bridges::cpp_uno::shared::VtableFactory::Slot
*
448 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block
)
450 return static_cast< Slot
* >(block
) + 2;
453 sal_Size
bridges::cpp_uno::shared::VtableFactory::getBlockSize(
456 return (slotCount
+ 2) * sizeof (Slot
) + slotCount
* codeSnippetSize
;
459 bridges::cpp_uno::shared::VtableFactory::Slot
*
460 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
461 void * block
, sal_Int32 slotCount
)
463 Slot
* slots
= mapBlockToVtable(block
);
466 return slots
+ slotCount
;
469 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
470 Slot
** slots
, unsigned char * code
, sal_PtrDiff writetoexecdiff
,
471 typelib_InterfaceTypeDescription
const * type
, sal_Int32 functionOffset
,
472 sal_Int32 functionCount
, sal_Int32 vtableOffset
)
474 (*slots
) -= functionCount
;
476 for (sal_Int32 i
= 0; i
< type
->nMembers
; ++i
)
478 typelib_TypeDescription
* member
= 0;
479 TYPELIB_DANGER_GET(&member
, type
->ppMembers
[i
]);
480 OSL_ASSERT(member
!= 0);
481 switch (member
->eTypeClass
)
483 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
485 (s
++)->fn
= code
+ writetoexecdiff
;
487 code
, functionOffset
++, vtableOffset
,
488 bridges::cpp_uno::shared::isSimpleType(
490 typelib_InterfaceAttributeTypeDescription
* >(
491 member
)->pAttributeTypeRef
));
493 if (!reinterpret_cast<
494 typelib_InterfaceAttributeTypeDescription
* >(
497 (s
++)->fn
= code
+ writetoexecdiff
;
499 code
, functionOffset
++, vtableOffset
, true);
502 case typelib_TypeClass_INTERFACE_METHOD
:
504 (s
++)->fn
= code
+ writetoexecdiff
;
506 typelib_InterfaceMethodTypeDescription
*pMethodTD
=
508 typelib_InterfaceMethodTypeDescription
* >(member
);
510 bool issimple
= bridges::cpp_uno::shared::isSimpleType(
511 pMethodTD
->pReturnTypeRef
);
513 code
= codeSnippet(code
, functionOffset
++, vtableOffset
,
521 TYPELIB_DANGER_RELEASE(member
);
526 void bridges::cpp_uno::shared::VtableFactory::flushCode(
527 unsigned char const *beg
, unsigned char const *end
)
529 static void (*clear_cache
)(unsigned char const*, unsigned char const*)
530 = (void (*)(unsigned char const*, unsigned char const*))
531 dlsym(RTLD_DEFAULT
, "__clear_cache");
532 (*clear_cache
)(beg
, end
);
535 /* vi:set tabstop=4 shiftwidth=4 expandtab: */