Bump for 3.6-28
[LibreOffice.git] / bridges / source / cpp_uno / msvc_win32_x86-64 / cpp2uno.cxx
blob6e2e343cf874cf8ff8caae83b31a494c4517bb70
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 <malloc.h>
32 #include <com/sun/star/uno/genfunc.hxx>
33 #include <uno/data.h>
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"
41 #include "mscx.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
49 sal_Int32 nParams,
50 typelib_MethodParameter * pParams,
51 void ** pStack )
53 // Return type
54 typelib_TypeDescription * pReturnTD = NULL;
55 if ( pReturnTypeRef )
56 TYPELIB_DANGER_GET( &pReturnTD, pReturnTypeRef );
58 int nFirstRealParam = 3; // Index into pStack, past return
59 // value, return address and 'this'
60 // pointer.
62 void * pUnoReturn = NULL;
63 void * pCppReturn = NULL; // Complex return ptr: if != NULL && != pUnoReturn, reconversion need
65 if ( pReturnTD )
67 if ( bridges::cpp_uno::shared::isSimpleType( pReturnTD ) )
69 pUnoReturn = pStack;
71 else
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)
93 int * pTempIndexes =
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 );
109 if ( !rParam.bOut &&
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
118 void * pCppStack;
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 ),
135 pCppStack, pParamTD,
136 pThis->getBridge()->getCpp2Uno() );
137 pTempIndexes[nTempIndexes] = nPos; // Has to be reconverted
138 // pParamTD will be released at reconversion
139 ppTempParamTD[nTempIndexes++] = pParamTD;
141 else // direct way
143 pUnoArgs[nPos] = pCppStack;
144 // No longer needed
145 TYPELIB_DANGER_RELEASE( pParamTD );
150 // ExceptionHolder
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...
159 if ( pUnoExc )
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] );
172 if ( pReturnTD )
173 TYPELIB_DANGER_RELEASE( pReturnTD );
175 CPPU_CURRENT_NAMESPACE::mscx_raiseException(
176 &aUnoExc, pThis->getBridge()->getUno2Cpp() ); // Has to destruct the any
178 // Is here for dummy
179 return typelib_TypeClass_VOID;
181 else // Else, no exception occurred...
183 // Temporary params
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
192 ::uno_destructData(
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 );
203 // Return
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;
217 if ( pReturnTD )
219 typelib_TypeClass eRet = (typelib_TypeClass)pReturnTD->eTypeClass;
220 TYPELIB_DANGER_RELEASE( pReturnTD );
221 return eRet;
223 else
224 return typelib_TypeClass_VOID;
228 extern "C" typelib_TypeClass cpp_vtable_call(
229 sal_Int64 nOffsetAndIndex,
230 void ** pStack )
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 )
273 // is GET method
274 eRet = cpp2uno_call( pCppI, aMemberDescr.get(), pAttrTypeRef,
275 0, NULL, // No params
276 pStack );
278 else
280 // is SET method
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
288 1, &aParam,
289 pStack );
291 break;
293 case typelib_TypeClass_INTERFACE_METHOD:
295 // is METHOD
296 switch ( nFunctionIndex )
298 case 1: // acquire()
299 pCppI->acquireProxy(); // Non virtual call!
300 eRet = typelib_TypeClass_VOID;
301 break;
302 case 2: // release()
303 pCppI->releaseProxy(); // non virtual call!
304 eRet = typelib_TypeClass_VOID;
305 break;
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() );
317 if ( pTD )
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 ) );
326 if ( pInterface )
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;
336 break;
338 TYPELIB_DANGER_RELEASE( pTD );
340 } // Fall through!
341 default:
343 typelib_InterfaceMethodTypeDescription * pMethodTD =
344 reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( aMemberDescr.get() );
346 eRet = cpp2uno_call( pCppI, aMemberDescr.get(),
347 pMethodTD->pReturnTypeRef,
348 pMethodTD->nParams,
349 pMethodTD->pParams,
350 pStack );
353 break;
355 default:
357 throw RuntimeException( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("No member description found!")),
358 reinterpret_cast<XInterface *>( pCppI ) );
362 return eRet;
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,
377 char param_kind[4],
378 sal_Int32 nFunctionIndex,
379 sal_Int32 nVtableOffset )
381 sal_uInt64 nOffsetAndIndex = ( ( (sal_uInt64) nVtableOffset ) << 32 ) | ( (sal_uInt64) nFunctionIndex );
382 unsigned char *p = code;
384 // Spill parameters
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;
390 else
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;
400 else
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;
410 else
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;
420 else
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;
434 // jmp r11
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(
446 void * block )
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(
459 void * block,
460 sal_Int32 slotCount )
462 struct Rtti {
463 sal_Int32 n0, n1, n2;
464 type_info * rtti;
465 Rtti():
466 n0(0), n1(0), n2(0),
467 rtti(CPPU_CURRENT_NAMESPACE::mscx_getRTTI(
468 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
469 "com.sun.star.uno.XInterface"))))
472 static Rtti rtti;
474 Slot * slots = mapBlockToVtable(block);
475 slots[-1].fn = &rtti;
476 return slots + slotCount;
479 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
480 Slot ** slots,
481 unsigned char * code,
482 typelib_InterfaceTypeDescription const * type,
483 sal_Int32 nFunctionOffset,
484 sal_Int32 functionCount,
485 sal_Int32 nVtableOffset )
487 (*slots) -= functionCount;
488 Slot * s = *slots;
490 for (int member = 0; member < type->nMembers; ++member) {
491 typelib_TypeDescription * pTD = NULL;
493 TYPELIB_DANGER_GET( &pTD, type->ppMembers[ member ] );
494 OSL_ASSERT( pTD );
496 char param_kind[4];
497 int nr = 0;
499 for (int i = 0; i < 4; ++i)
500 param_kind[i] = CPPU_CURRENT_NAMESPACE::REGPARAM_INT;
502 // 'this'
503 ++nr;
505 if ( pTD->eTypeClass == typelib_TypeClass_INTERFACE_ATTRIBUTE )
507 typelib_InterfaceAttributeTypeDescription * pIfaceAttrTD =
508 reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( pTD );
510 // Getter
512 (s++)->fn = code;
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 );
520 // Setter
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 );
527 (s++)->fn = code;
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 ) )
542 // Return value
543 ++nr;
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 );
559 (s++)->fn = code;
560 code = codeSnippet( code, param_kind, nFunctionOffset++, nVtableOffset );
562 TYPELIB_DANGER_RELEASE( pReturnTD );
564 else
565 OSL_ASSERT( false );
567 TYPELIB_DANGER_RELEASE( pTD );
569 return code;
572 void bridges::cpp_uno::shared::VtableFactory::flushCode(
573 unsigned char const *,
574 unsigned char const * )
578 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */