1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include <sal/alloca.h>
33 #include <com/sun/star/uno/genfunc.hxx>
34 #include "com/sun/star/uno/RuntimeException.hpp"
36 #include <typelib/typedescription.hxx>
38 #include "bridges/cpp_uno/shared/bridge.hxx"
39 #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx"
40 #include "bridges/cpp_uno/shared/types.hxx"
41 #include "bridges/cpp_uno/shared/vtablefactory.hxx"
45 using namespace ::com::sun::star::uno
;
50 //==================================================================================================
51 static typelib_TypeClass
cpp2uno_call(
52 bridges::cpp_uno::shared::CppInterfaceProxy
* pThis
,
53 const typelib_TypeDescription
* pMemberTypeDescr
,
54 typelib_TypeDescriptionReference
* pReturnTypeRef
, // 0 indicates void return
55 sal_Int32 nParams
, typelib_MethodParameter
* pParams
,
57 sal_Int64
* pRegisterReturn
/* space for register return */ )
59 // pCallStack: ret, [return ptr], this, params
60 char * pCppStack
= (char *)(pCallStack
+1);
63 typelib_TypeDescription
* pReturnTypeDescr
= 0;
65 TYPELIB_DANGER_GET( &pReturnTypeDescr
, pReturnTypeRef
);
67 void * pUnoReturn
= 0;
68 void * pCppReturn
= 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
72 if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr
))
74 pUnoReturn
= pRegisterReturn
; // direct way for simple types
76 else // complex return via ptr (pCppReturn)
78 pCppReturn
= *(void **)pCppStack
;
79 pCppStack
+= sizeof(void *);
81 pUnoReturn
= (bridges::cpp_uno::shared::relatesToInterfaceType(
83 ? alloca( pReturnTypeDescr
->nSize
)
84 : pCppReturn
); // direct way
88 pCppStack
+= sizeof( void* );
91 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32
), "### unexpected size!" );
93 void ** pUnoArgs
= (void **)alloca( 4 * sizeof(void *) * nParams
);
94 void ** pCppArgs
= pUnoArgs
+ nParams
;
95 // indizes of values this have to be converted (interface conversion cpp<=>uno)
96 sal_Int32
* pTempIndizes
= (sal_Int32
*)(pUnoArgs
+ (2 * nParams
));
97 // type descriptions for reconversions
98 typelib_TypeDescription
** ppTempParamTypeDescr
= (typelib_TypeDescription
**)(pUnoArgs
+ (3 * nParams
));
100 sal_Int32 nTempIndizes
= 0;
102 for ( sal_Int32 nPos
= 0; nPos
< nParams
; ++nPos
)
104 const typelib_MethodParameter
& rParam
= pParams
[nPos
];
105 typelib_TypeDescription
* pParamTypeDescr
= 0;
106 TYPELIB_DANGER_GET( &pParamTypeDescr
, rParam
.pTypeRef
);
109 && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr
))
112 pCppArgs
[nPos
] = pCppStack
;
113 pUnoArgs
[nPos
] = pCppStack
;
114 switch (pParamTypeDescr
->eTypeClass
)
116 case typelib_TypeClass_HYPER
:
117 case typelib_TypeClass_UNSIGNED_HYPER
:
118 case typelib_TypeClass_DOUBLE
:
119 pCppStack
+= sizeof(sal_Int32
); // extra long
122 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
124 else // ptr to complex value | ref
126 pCppArgs
[nPos
] = *(void **)pCppStack
;
128 if (! rParam
.bIn
) // is pure out
130 // uno out is unconstructed mem!
131 pUnoArgs
[nPos
] = alloca( pParamTypeDescr
->nSize
);
132 pTempIndizes
[nTempIndizes
] = nPos
;
133 // will be released at reconversion
134 ppTempParamTypeDescr
[nTempIndizes
++] = pParamTypeDescr
;
137 else if (bridges::cpp_uno::shared::relatesToInterfaceType(
140 uno_copyAndConvertData( pUnoArgs
[nPos
] = alloca( pParamTypeDescr
->nSize
),
141 *(void **)pCppStack
, pParamTypeDescr
,
142 pThis
->getBridge()->getCpp2Uno() );
143 pTempIndizes
[nTempIndizes
] = nPos
; // has to be reconverted
144 // will be released at reconversion
145 ppTempParamTypeDescr
[nTempIndizes
++] = pParamTypeDescr
;
149 pUnoArgs
[nPos
] = *(void **)pCppStack
;
151 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
154 pCppStack
+= sizeof(sal_Int32
); // standard parameter length
158 uno_Any aUnoExc
; // Any will be constructed by callee
159 uno_Any
* pUnoExc
= &aUnoExc
;
161 // invoke uno dispatch call
162 (*pThis
->getUnoI()->pDispatcher
)(
163 pThis
->getUnoI(), pMemberTypeDescr
, pUnoReturn
, pUnoArgs
, &pUnoExc
);
165 // in case an exception occurred...
168 // destruct temporary in/inout params
169 for ( ; nTempIndizes
--; )
171 sal_Int32 nIndex
= pTempIndizes
[nTempIndizes
];
173 if (pParams
[nIndex
].bIn
) // is in/inout => was constructed
174 uno_destructData( pUnoArgs
[nIndex
], ppTempParamTypeDescr
[nTempIndizes
], 0 );
175 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr
[nTempIndizes
] );
177 if (pReturnTypeDescr
)
178 TYPELIB_DANGER_RELEASE( pReturnTypeDescr
);
180 CPPU_CURRENT_NAMESPACE::raiseException(
181 &aUnoExc
, pThis
->getBridge()->getUno2Cpp() );
182 // has to destruct the any
184 return typelib_TypeClass_VOID
;
186 else // else no exception occurred...
189 for ( ; nTempIndizes
--; )
191 sal_Int32 nIndex
= pTempIndizes
[nTempIndizes
];
192 typelib_TypeDescription
* pParamTypeDescr
= ppTempParamTypeDescr
[nTempIndizes
];
194 if (pParams
[nIndex
].bOut
) // inout/out
196 // convert and assign
197 uno_destructData( pCppArgs
[nIndex
], pParamTypeDescr
, cpp_release
);
198 uno_copyAndConvertData( pCppArgs
[nIndex
], pUnoArgs
[nIndex
], pParamTypeDescr
,
199 pThis
->getBridge()->getUno2Cpp() );
201 // destroy temp uno param
202 uno_destructData( pUnoArgs
[nIndex
], pParamTypeDescr
, 0 );
204 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
207 if (pCppReturn
) // has complex return
209 if (pUnoReturn
!= pCppReturn
) // needs reconversion
211 uno_copyAndConvertData( pCppReturn
, pUnoReturn
, pReturnTypeDescr
,
212 pThis
->getBridge()->getUno2Cpp() );
213 // destroy temp uno return
214 uno_destructData( pUnoReturn
, pReturnTypeDescr
, 0 );
216 // complex return ptr is set to eax
217 *(void **)pRegisterReturn
= pCppReturn
;
219 if (pReturnTypeDescr
)
221 typelib_TypeClass eRet
= (typelib_TypeClass
)pReturnTypeDescr
->eTypeClass
;
222 TYPELIB_DANGER_RELEASE( pReturnTypeDescr
);
226 return typelib_TypeClass_VOID
;
231 //==================================================================================================
232 static typelib_TypeClass
cpp_mediate(
233 sal_Int32 nFunctionIndex
,
234 sal_Int32 nVtableOffset
,
236 sal_Int64
* pRegisterReturn
/* space for register return */ )
238 OSL_ENSURE( sizeof(sal_Int32
)==sizeof(void *), "### unexpected!" );
240 // pCallStack: ret adr, [ret *], this, params
242 if( nFunctionIndex
& 0x80000000 )
244 nFunctionIndex
&= 0x7fffffff;
245 pThis
= pCallStack
[2];
249 pThis
= pCallStack
[1];
251 pThis
= static_cast< char * >(pThis
) - nVtableOffset
;
252 bridges::cpp_uno::shared::CppInterfaceProxy
* pCppI
253 = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
256 typelib_InterfaceTypeDescription
* pTypeDescr
= pCppI
->getTypeDescr();
258 OSL_ENSURE( nFunctionIndex
< pTypeDescr
->nMapFunctionIndexToMemberIndex
, "### illegal vtable index!" );
259 if (nFunctionIndex
>= pTypeDescr
->nMapFunctionIndexToMemberIndex
)
261 throw RuntimeException(
262 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "illegal vtable index!" )),
263 (XInterface
*)pThis
);
266 // determine called method
267 sal_Int32 nMemberPos
= pTypeDescr
->pMapFunctionIndexToMemberIndex
[nFunctionIndex
];
268 OSL_ENSURE( nMemberPos
< pTypeDescr
->nAllMembers
, "### illegal member index!" );
270 TypeDescription
aMemberDescr( pTypeDescr
->ppAllMembers
[nMemberPos
] );
272 typelib_TypeClass eRet
;
273 switch (aMemberDescr
.get()->eTypeClass
)
275 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
277 if (pTypeDescr
->pMapMemberIndexToFunctionIndex
[nMemberPos
] == nFunctionIndex
)
281 pCppI
, aMemberDescr
.get(),
282 ((typelib_InterfaceAttributeTypeDescription
*)aMemberDescr
.get())->pAttributeTypeRef
,
284 pCallStack
, pRegisterReturn
);
289 typelib_MethodParameter aParam
;
291 ((typelib_InterfaceAttributeTypeDescription
*)aMemberDescr
.get())->pAttributeTypeRef
;
292 aParam
.bIn
= sal_True
;
293 aParam
.bOut
= sal_False
;
296 pCppI
, aMemberDescr
.get(),
297 0, // indicates void return
299 pCallStack
, pRegisterReturn
);
303 case typelib_TypeClass_INTERFACE_METHOD
:
306 switch (nFunctionIndex
)
309 pCppI
->acquireProxy(); // non virtual call!
310 eRet
= typelib_TypeClass_VOID
;
313 pCppI
->releaseProxy(); // non virtual call!
314 eRet
= typelib_TypeClass_VOID
;
316 case 0: // queryInterface() opt
318 typelib_TypeDescription
* pTD
= 0;
319 TYPELIB_DANGER_GET( &pTD
, reinterpret_cast< Type
* >( pCallStack
[3] )->getTypeLibType() );
322 XInterface
* pInterface
= 0;
323 (*pCppI
->getBridge()->getCppEnv()->getRegisteredInterface
)(
324 pCppI
->getBridge()->getCppEnv(),
325 (void **)&pInterface
, pCppI
->getOid().pData
,
326 (typelib_InterfaceTypeDescription
*)pTD
);
331 reinterpret_cast< uno_Any
* >( pCallStack
[1] ),
332 &pInterface
, pTD
, cpp_acquire
);
333 pInterface
->release();
334 TYPELIB_DANGER_RELEASE( pTD
);
335 *(void **)pRegisterReturn
= pCallStack
[1];
336 eRet
= typelib_TypeClass_ANY
;
339 TYPELIB_DANGER_RELEASE( pTD
);
341 } // else perform queryInterface()
344 pCppI
, aMemberDescr
.get(),
345 ((typelib_InterfaceMethodTypeDescription
*)aMemberDescr
.get())->pReturnTypeRef
,
346 ((typelib_InterfaceMethodTypeDescription
*)aMemberDescr
.get())->nParams
,
347 ((typelib_InterfaceMethodTypeDescription
*)aMemberDescr
.get())->pParams
,
348 pCallStack
, pRegisterReturn
);
354 throw RuntimeException(
355 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "no member description found!" )),
356 (XInterface
*)pThis
);
363 //==================================================================================================
365 * is called on incoming vtable calls
366 * (called by asm snippets)
368 static void cpp_vtable_call(
369 int nFunctionIndex
, int nVtableOffset
, void** pCallStack
)
370 __attribute__((regparm(3)));
372 void cpp_vtable_call( int nFunctionIndex
, int nVtableOffset
, void** pCallStack
)
374 volatile long nRegReturn
[2];
375 typelib_TypeClass aType
= cpp_mediate(
376 nFunctionIndex
, nVtableOffset
, pCallStack
, (sal_Int64
*)nRegReturn
);
380 case typelib_TypeClass_HYPER
:
381 case typelib_TypeClass_UNSIGNED_HYPER
:
382 __asm__( "movl %1, %%edx\n\t"
384 : : "m"(nRegReturn
[0]), "m"(nRegReturn
[1]) );
386 case typelib_TypeClass_FLOAT
:
387 __asm__( "flds %0\n\t"
390 : : "m"(*(float *)nRegReturn
) );
392 case typelib_TypeClass_DOUBLE
:
393 __asm__( "fldl %0\n\t"
396 : : "m"(*(double *)nRegReturn
) );
398 // case typelib_TypeClass_UNSIGNED_SHORT:
399 // case typelib_TypeClass_SHORT:
400 // __asm__( "movswl %0, %%eax\n"
401 // : : "m"(nRegReturn) );
404 __asm__( "movl %0, %%eax\n"
405 : : "m"(nRegReturn
[0]) );
411 //==================================================================================================
412 int const codeSnippetSize
= 20;
414 unsigned char * codeSnippet(
415 unsigned char * code
, sal_Int32 functionIndex
, sal_Int32 vtableOffset
,
418 if (!simpleRetType
) {
419 functionIndex
|= 0x80000000;
421 unsigned char * p
= code
;
422 OSL_ASSERT(sizeof (sal_Int32
) == 4);
423 // mov function_index, %eax:
425 *reinterpret_cast< sal_Int32
* >(p
) = functionIndex
;
426 p
+= sizeof (sal_Int32
);
427 // mov vtable_offset, %edx:
429 *reinterpret_cast< sal_Int32
* >(p
) = vtableOffset
;
430 p
+= sizeof (sal_Int32
);
434 // jmp cpp_vtable_call:
436 *reinterpret_cast< sal_Int32
* >(p
)
437 = ((unsigned char *) cpp_vtable_call
) - p
- sizeof (sal_Int32
);
438 p
+= sizeof (sal_Int32
);
439 OSL_ASSERT(p
- code
<= codeSnippetSize
);
440 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
,
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
) {
477 typelib_TypeDescription
* member
= 0;
478 TYPELIB_DANGER_GET(&member
, type
->ppMembers
[i
]);
479 OSL_ASSERT(member
!= 0);
480 switch (member
->eTypeClass
) {
481 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
485 code
, functionOffset
++, vtableOffset
,
486 bridges::cpp_uno::shared::isSimpleType(
488 typelib_InterfaceAttributeTypeDescription
* >(
489 member
)->pAttributeTypeRef
));
491 if (!reinterpret_cast<
492 typelib_InterfaceAttributeTypeDescription
* >(
496 code
= codeSnippet(code
, functionOffset
++, vtableOffset
, true);
500 case typelib_TypeClass_INTERFACE_METHOD
:
503 code
, functionOffset
++, vtableOffset
,
504 bridges::cpp_uno::shared::isSimpleType(
506 typelib_InterfaceMethodTypeDescription
* >(
507 member
)->pReturnTypeRef
));
514 TYPELIB_DANGER_RELEASE(member
);
519 void bridges::cpp_uno::shared::VtableFactory::flushCode(
520 unsigned char const *, unsigned char const *)
523 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */