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 ************************************************************************/
32 #include <com/sun/star/uno/genfunc.hxx>
34 #include <typelib/typedescription.hxx>
36 #include "bridges/cpp_uno/shared/bridge.hxx"
37 #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx"
38 #include "bridges/cpp_uno/shared/types.hxx"
39 #include "bridges/cpp_uno/shared/vtablefactory.hxx"
43 using namespace ::com::sun::star::uno
;
45 static inline typelib_TypeClass
cpp2uno_call(
46 bridges::cpp_uno::shared::CppInterfaceProxy
* pThis
,
47 const typelib_TypeDescription
* pMemberTD
,
48 typelib_TypeDescriptionReference
* pReturnTypeRef
, // NULL indicates void return
50 typelib_MethodParameter
* pParams
,
54 typelib_TypeDescription
* pReturnTD
= NULL
;
56 TYPELIB_DANGER_GET( &pReturnTD
, pReturnTypeRef
);
58 int nFirstRealParam
= 3; // Index into pStack, past return
59 // value, return address and 'this'
62 void * pUnoReturn
= NULL
;
63 void * pCppReturn
= NULL
; // Complex return ptr: if != NULL && != pUnoReturn, reconversion need
67 if ( bridges::cpp_uno::shared::isSimpleType( pReturnTD
) )
73 pCppReturn
= pStack
[nFirstRealParam
++];
75 pUnoReturn
= ( bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTD
)
76 ? alloca( pReturnTD
->nSize
)
77 : pCppReturn
); // direct way
81 void ** pCppIncomingParams
= pStack
+ nFirstRealParam
;
83 // Unlike this method for other archs, prefer clarity to
84 // micro-optimization, and allocate these array separately
86 // Parameters passed to the UNO function
87 void ** pUnoArgs
= (void **)alloca( sizeof(void *) * nParams
);
89 // Parameters received from C++
90 void ** pCppArgs
= (void **)alloca( sizeof(void *) * nParams
);
92 // Indexes of values this have to be converted (interface conversion C++<=>UNO)
94 (int *)alloca( sizeof(int) * nParams
);
96 // Type descriptions for reconversions
97 typelib_TypeDescription
** ppTempParamTD
=
98 (typelib_TypeDescription
**)alloca( sizeof(void *) * nParams
);
100 int nTempIndexes
= 0;
102 for ( int nPos
= 0; nPos
< nParams
; ++nPos
)
104 const typelib_MethodParameter
& rParam
= pParams
[nPos
];
106 typelib_TypeDescription
* pParamTD
= NULL
;
107 TYPELIB_DANGER_GET( &pParamTD
, rParam
.pTypeRef
);
110 bridges::cpp_uno::shared::isSimpleType( pParamTD
) )
112 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = pCppIncomingParams
++;
114 TYPELIB_DANGER_RELEASE( pParamTD
);
116 else // ptr to complex value | ref
120 pCppArgs
[nPos
] = pCppStack
= *pCppIncomingParams
++;
122 if ( !rParam
.bIn
) // Pure out
124 // UNO out is unconstructed mem
125 pUnoArgs
[nPos
] = alloca( pParamTD
->nSize
);
126 pTempIndexes
[nTempIndexes
] = nPos
;
127 // pParamTD will be released at reconversion
128 ppTempParamTD
[nTempIndexes
++] = pParamTD
;
131 else if ( bridges::cpp_uno::shared::relatesToInterfaceType( pParamTD
) )
133 ::uno_copyAndConvertData(
134 pUnoArgs
[nPos
] = alloca( pParamTD
->nSize
),
136 pThis
->getBridge()->getCpp2Uno() );
137 pTempIndexes
[nTempIndexes
] = nPos
; // Has to be reconverted
138 // pParamTD will be released at reconversion
139 ppTempParamTD
[nTempIndexes
++] = pParamTD
;
143 pUnoArgs
[nPos
] = pCppStack
;
145 TYPELIB_DANGER_RELEASE( pParamTD
);
151 uno_Any aUnoExc
; // Any will be constructed by callee
152 uno_Any
* pUnoExc
= &aUnoExc
;
154 // invoke UNO dispatch call
155 (*pThis
->getUnoI()->pDispatcher
)(
156 pThis
->getUnoI(), pMemberTD
, pUnoReturn
, pUnoArgs
, &pUnoExc
);
158 // in case an exception occurred...
161 // Destruct temporary in/inout params
162 while ( nTempIndexes
-- )
164 int nIndex
= pTempIndexes
[nTempIndexes
];
166 if ( pParams
[nIndex
].bIn
) // Is in/inout => was constructed
168 ::uno_destructData( pUnoArgs
[nIndex
], ppTempParamTD
[nTempIndexes
], 0 );
170 TYPELIB_DANGER_RELEASE( ppTempParamTD
[nTempIndexes
] );
173 TYPELIB_DANGER_RELEASE( pReturnTD
);
175 CPPU_CURRENT_NAMESPACE::mscx_raiseException(
176 &aUnoExc
, pThis
->getBridge()->getUno2Cpp() ); // Has to destruct the any
179 return typelib_TypeClass_VOID
;
181 else // Else, no exception occurred...
184 while (nTempIndexes
--)
186 int nIndex
= pTempIndexes
[nTempIndexes
];
187 typelib_TypeDescription
* pParamTD
= ppTempParamTD
[nTempIndexes
];
189 if ( pParams
[nIndex
].bOut
) // inout/out
191 // Convert and assign
193 pCppArgs
[nIndex
], pParamTD
, cpp_release
);
194 ::uno_copyAndConvertData(
195 pCppArgs
[nIndex
], pUnoArgs
[nIndex
], pParamTD
,
196 pThis
->getBridge()->getUno2Cpp() );
198 // Destroy temp UNO param
199 ::uno_destructData( pUnoArgs
[nIndex
], pParamTD
, 0 );
201 TYPELIB_DANGER_RELEASE( pParamTD
);
204 if ( pCppReturn
) // Has complex return
206 if ( pUnoReturn
!= pCppReturn
) // Needs reconversion
208 ::uno_copyAndConvertData(
209 pCppReturn
, pUnoReturn
, pReturnTD
,
210 pThis
->getBridge()->getUno2Cpp() );
211 // Destroy temp UNO return
212 ::uno_destructData( pUnoReturn
, pReturnTD
, 0 );
214 // Complex return ptr is set to eax
215 pStack
[0] = pCppReturn
;
219 typelib_TypeClass eRet
= (typelib_TypeClass
)pReturnTD
->eTypeClass
;
220 TYPELIB_DANGER_RELEASE( pReturnTD
);
224 return typelib_TypeClass_VOID
;
228 extern "C" typelib_TypeClass
cpp_vtable_call(
229 sal_Int64 nOffsetAndIndex
,
232 sal_Int32 nFunctionIndex
= (nOffsetAndIndex
& 0xFFFFFFFF);
233 sal_Int32 nVtableOffset
= ((nOffsetAndIndex
>> 32) & 0xFFFFFFFF);
235 // pStack points to space for return value allocated by
236 // privateSnippetExecutor() in call.asm, after which follows our
237 // return address (uninteresting), then the integer or
238 // floating-point register parameters (spilled by
239 // privateSnippetExecutor()) from the call to the trampoline,
240 // followed by stacked parameters. The first parameter is the
241 // 'this' pointer. If the callee returns a large value, the
242 // parameter after that is actually a pointer to where the callee
243 // should store its return value.
245 void * pThis
= static_cast<char *>( pStack
[2] ) - nVtableOffset
;
247 bridges::cpp_uno::shared::CppInterfaceProxy
* pCppI
=
248 bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( pThis
);
250 typelib_InterfaceTypeDescription
* pTD
= pCppI
->getTypeDescr();
252 OSL_ENSURE( nFunctionIndex
< pTD
->nMapFunctionIndexToMemberIndex
, "### illegal vtable index!\n" );
253 if ( nFunctionIndex
>= pTD
->nMapFunctionIndexToMemberIndex
)
254 throw RuntimeException( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Illegal vtable index!")),
255 reinterpret_cast<XInterface
*>( pCppI
) );
257 // Determine called method
258 int nMemberPos
= pTD
->pMapFunctionIndexToMemberIndex
[nFunctionIndex
];
259 OSL_ENSURE( nMemberPos
< pTD
->nAllMembers
, "### illegal member index!\n" );
261 TypeDescription
aMemberDescr( pTD
->ppAllMembers
[nMemberPos
] );
263 typelib_TypeClass eRet
;
264 switch ( aMemberDescr
.get()->eTypeClass
)
266 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
268 typelib_TypeDescriptionReference
*pAttrTypeRef
=
269 reinterpret_cast<typelib_InterfaceAttributeTypeDescription
*>( aMemberDescr
.get() )->pAttributeTypeRef
;
271 if ( pTD
->pMapMemberIndexToFunctionIndex
[nMemberPos
] == nFunctionIndex
)
274 eRet
= cpp2uno_call( pCppI
, aMemberDescr
.get(), pAttrTypeRef
,
275 0, NULL
, // No params
281 typelib_MethodParameter aParam
;
282 aParam
.pTypeRef
= pAttrTypeRef
;
283 aParam
.bIn
= sal_True
;
284 aParam
.bOut
= sal_False
;
286 eRet
= cpp2uno_call( pCppI
, aMemberDescr
.get(),
287 NULL
, // Indicates void return
293 case typelib_TypeClass_INTERFACE_METHOD
:
296 switch ( nFunctionIndex
)
299 pCppI
->acquireProxy(); // Non virtual call!
300 eRet
= typelib_TypeClass_VOID
;
303 pCppI
->releaseProxy(); // non virtual call!
304 eRet
= typelib_TypeClass_VOID
;
306 case 0: // queryInterface() opt
308 typelib_TypeDescription
* pTD
= NULL
;
310 // the incoming C++ parameters are: The this
311 // pointer, the hidden return value pointer, and
312 // then the actual queryInterface() only
313 // parameter. Thus pStack[4]..
315 TYPELIB_DANGER_GET( &pTD
, reinterpret_cast<Type
*>( pStack
[4] )->getTypeLibType() );
319 XInterface
* pInterface
= NULL
;
320 (*pCppI
->getBridge()->getCppEnv()->getRegisteredInterface
)
321 ( pCppI
->getBridge()->getCppEnv(),
322 (void **)&pInterface
,
323 pCppI
->getOid().pData
,
324 reinterpret_cast<typelib_InterfaceTypeDescription
*>( pTD
) );
328 // pStack[3] = hidden return value pointer
329 ::uno_any_construct( reinterpret_cast<uno_Any
*>( pStack
[3] ),
330 &pInterface
, pTD
, cpp_acquire
);
332 pInterface
->release();
333 TYPELIB_DANGER_RELEASE( pTD
);
335 eRet
= typelib_TypeClass_ANY
;
338 TYPELIB_DANGER_RELEASE( pTD
);
343 typelib_InterfaceMethodTypeDescription
* pMethodTD
=
344 reinterpret_cast<typelib_InterfaceMethodTypeDescription
*>( aMemberDescr
.get() );
346 eRet
= cpp2uno_call( pCppI
, aMemberDescr
.get(),
347 pMethodTD
->pReturnTypeRef
,
357 throw RuntimeException( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("No member description found!")),
358 reinterpret_cast<XInterface
*>( pCppI
) );
365 int const codeSnippetSize
= 48;
367 extern "C" char privateSnippetExecutor
;
369 // This function generates the code that acts as a proxy for the UNO function to be called.
370 // The generated code does the following:
371 // - Spills register parameters on stack
372 // - Loads functionIndex and vtableOffset into scratch registers
373 // - Jumps to privateSnippetExecutor
375 unsigned char * codeSnippet(
376 unsigned char * code
,
378 sal_Int32 nFunctionIndex
,
379 sal_Int32 nVtableOffset
)
381 sal_uInt64 nOffsetAndIndex
= ( ( (sal_uInt64
) nVtableOffset
) << 32 ) | ( (sal_uInt64
) nFunctionIndex
);
382 unsigned char *p
= code
;
385 if ( param_kind
[0] == CPPU_CURRENT_NAMESPACE::REGPARAM_INT
)
387 // mov qword ptr 8[rsp], rcx
388 *p
++ = 0x48; *p
++ = 0x89; *p
++ = 0x4C; *p
++ = 0x24; *p
++ = 0x08;
392 // movsd qword ptr 8[rsp], xmm0
393 *p
++ = 0xF2; *p
++ = 0x0F; *p
++ = 0x11; *p
++ = 0x44; *p
++ = 0x24; *p
++ = 0x08;
395 if ( param_kind
[1] == CPPU_CURRENT_NAMESPACE::REGPARAM_INT
)
397 // mov qword ptr 16[rsp], rdx
398 *p
++ = 0x48; *p
++ = 0x89; *p
++ = 0x54; *p
++ = 0x24; *p
++ = 0x10;
402 // movsd qword ptr 16[rsp], xmm1
403 *p
++ = 0xF2; *p
++ = 0x0F; *p
++ = 0x11; *p
++ = 0x4C; *p
++ = 0x24; *p
++ = 0x10;
405 if ( param_kind
[2] == CPPU_CURRENT_NAMESPACE::REGPARAM_INT
)
407 // mov qword ptr 24[rsp], r8
408 *p
++ = 0x4C; *p
++ = 0x89; *p
++ = 0x44; *p
++ = 0x24; *p
++ = 0x18;
412 // movsd qword ptr 24[rsp], xmm2
413 *p
++ = 0xF2; *p
++ = 0x0F; *p
++ = 0x11; *p
++ = 0x54; *p
++ = 0x24; *p
++ = 0x18;
415 if ( param_kind
[3] == CPPU_CURRENT_NAMESPACE::REGPARAM_INT
)
417 // mov qword ptr 32[rsp], r9
418 *p
++ = 0x4C;*p
++ = 0x89; *p
++ = 0x4C; *p
++ = 0x24; *p
++ = 0x20;
422 // movsd qword ptr 32[rsp], xmm3
423 *p
++ = 0xF2; *p
++ = 0x0F; *p
++ = 0x11; *p
++ = 0x5C; *p
++ = 0x24; *p
++ = 0x20;
426 // mov rcx, nOffsetAndIndex
427 *p
++ = 0x48; *p
++ = 0xB9;
428 *((sal_uInt64
*)p
) = nOffsetAndIndex
; p
+= 8;
430 // mov r11, privateSnippetExecutor
431 *p
++ = 0x49; *p
++ = 0xBB;
432 *((void **)p
) = &privateSnippetExecutor
; p
+= 8;
435 *p
++ = 0x41; *p
++ = 0xFF; *p
++ = 0xE3;
437 OSL_ASSERT( p
< code
+ codeSnippetSize
);
439 return code
+ codeSnippetSize
;
442 struct bridges::cpp_uno::shared::VtableFactory::Slot
{ void * fn
; };
444 bridges::cpp_uno::shared::VtableFactory::Slot
*
445 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(
448 return static_cast< Slot
* >(block
) + 1;
451 sal_Size
bridges::cpp_uno::shared::VtableFactory::getBlockSize(
452 sal_Int32 slotCount
)
454 return (slotCount
+ 1) * sizeof (Slot
) + slotCount
* codeSnippetSize
;
457 bridges::cpp_uno::shared::VtableFactory::Slot
*
458 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
460 sal_Int32 slotCount
)
463 sal_Int32 n0
, n1
, n2
;
467 rtti(CPPU_CURRENT_NAMESPACE::mscx_getRTTI(
468 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
469 "com.sun.star.uno.XInterface"))))
474 Slot
* slots
= mapBlockToVtable(block
);
475 slots
[-1].fn
= &rtti
;
476 return slots
+ slotCount
;
479 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
481 unsigned char * code
,
482 typelib_InterfaceTypeDescription
const * type
,
483 sal_Int32 nFunctionOffset
,
484 sal_Int32 functionCount
,
485 sal_Int32 nVtableOffset
)
487 (*slots
) -= functionCount
;
490 for (int member
= 0; member
< type
->nMembers
; ++member
) {
491 typelib_TypeDescription
* pTD
= NULL
;
493 TYPELIB_DANGER_GET( &pTD
, type
->ppMembers
[ member
] );
499 for (int i
= 0; i
< 4; ++i
)
500 param_kind
[i
] = CPPU_CURRENT_NAMESPACE::REGPARAM_INT
;
505 if ( pTD
->eTypeClass
== typelib_TypeClass_INTERFACE_ATTRIBUTE
)
507 typelib_InterfaceAttributeTypeDescription
* pIfaceAttrTD
=
508 reinterpret_cast<typelib_InterfaceAttributeTypeDescription
*>( pTD
);
513 code
= codeSnippet( code
, param_kind
, nFunctionOffset
++, nVtableOffset
);
514 if ( ! pIfaceAttrTD
->bReadOnly
)
516 typelib_TypeDescription
* pAttrTD
= NULL
;
517 TYPELIB_DANGER_GET( &pAttrTD
, pIfaceAttrTD
->pAttributeTypeRef
);
518 OSL_ASSERT( pAttrTD
);
521 if ( pAttrTD
->eTypeClass
== typelib_TypeClass_FLOAT
||
522 pAttrTD
->eTypeClass
== typelib_TypeClass_DOUBLE
)
523 param_kind
[nr
++] = CPPU_CURRENT_NAMESPACE::REGPARAM_FLT
;
525 TYPELIB_DANGER_RELEASE( pAttrTD
);
528 code
= codeSnippet( code
, param_kind
, nFunctionOffset
++, nVtableOffset
);
531 else if ( pTD
->eTypeClass
== typelib_TypeClass_INTERFACE_METHOD
)
533 typelib_InterfaceMethodTypeDescription
* pMethodTD
=
534 reinterpret_cast<typelib_InterfaceMethodTypeDescription
*>( pTD
);
536 typelib_TypeDescription
* pReturnTD
= NULL
;
537 TYPELIB_DANGER_GET( &pReturnTD
, pMethodTD
->pReturnTypeRef
);
538 OSL_ASSERT( pReturnTD
);
540 if ( !bridges::cpp_uno::shared::isSimpleType( pReturnTD
) )
546 for (int param
= 0; nr
< 4 && param
< pMethodTD
->nParams
; ++param
, ++nr
)
548 typelib_TypeDescription
* pParamTD
= NULL
;
550 TYPELIB_DANGER_GET( &pParamTD
, pMethodTD
->pParams
[param
].pTypeRef
);
551 OSL_ASSERT( pParamTD
);
553 if ( pParamTD
->eTypeClass
== typelib_TypeClass_FLOAT
||
554 pParamTD
->eTypeClass
== typelib_TypeClass_DOUBLE
)
555 param_kind
[nr
] = CPPU_CURRENT_NAMESPACE::REGPARAM_FLT
;
557 TYPELIB_DANGER_RELEASE( pParamTD
);
560 code
= codeSnippet( code
, param_kind
, nFunctionOffset
++, nVtableOffset
);
562 TYPELIB_DANGER_RELEASE( pReturnTD
);
567 TYPELIB_DANGER_RELEASE( pTD
);
572 void bridges::cpp_uno::shared::VtableFactory::flushCode(
573 unsigned char const *,
574 unsigned char const * )
578 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */