12755751fSHerbert Dürr /**************************************************************
22755751fSHerbert Dürr  *
32755751fSHerbert Dürr  * Licensed to the Apache Software Foundation (ASF) under one
42755751fSHerbert Dürr  * or more contributor license agreements.  See the NOTICE file
52755751fSHerbert Dürr  * distributed with this work for additional information
62755751fSHerbert Dürr  * regarding copyright ownership.  The ASF licenses this file
72755751fSHerbert Dürr  * to you under the Apache License, Version 2.0 (the
82755751fSHerbert Dürr  * "License"); you may not use this file except in compliance
92755751fSHerbert Dürr  * with the License.  You may obtain a copy of the License at
102755751fSHerbert Dürr  *
112755751fSHerbert Dürr  *   http://www.apache.org/licenses/LICENSE-2.0
122755751fSHerbert Dürr  *
132755751fSHerbert Dürr  * Unless required by applicable law or agreed to in writing,
142755751fSHerbert Dürr  * software distributed under the License is distributed on an
152755751fSHerbert Dürr  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
162755751fSHerbert Dürr  * KIND, either express or implied.  See the License for the
172755751fSHerbert Dürr  * specific language governing permissions and limitations
182755751fSHerbert Dürr  * under the License.
192755751fSHerbert Dürr  *
202755751fSHerbert Dürr  *************************************************************/
212755751fSHerbert Dürr 
222755751fSHerbert Dürr 
232755751fSHerbert Dürr 
242755751fSHerbert Dürr // MARKER(update_precomp.py): autogen include statement, do not remove
252755751fSHerbert Dürr #include "precompiled_bridges.hxx"
262755751fSHerbert Dürr 
272755751fSHerbert Dürr #include <stdio.h>
282755751fSHerbert Dürr #include <stdlib.h>
292755751fSHerbert Dürr #include <hash_map>
302755751fSHerbert Dürr 
312755751fSHerbert Dürr #include <rtl/alloc.h>
322755751fSHerbert Dürr #include <osl/mutex.hxx>
332755751fSHerbert Dürr 
342755751fSHerbert Dürr #include <com/sun/star/uno/genfunc.hxx>
352755751fSHerbert Dürr #include "com/sun/star/uno/RuntimeException.hpp"
362755751fSHerbert Dürr #include <uno/data.h>
372755751fSHerbert Dürr #include <typelib/typedescription.hxx>
382755751fSHerbert Dürr 
392755751fSHerbert Dürr #include "bridges/cpp_uno/shared/bridge.hxx"
402755751fSHerbert Dürr #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx"
412755751fSHerbert Dürr #include "bridges/cpp_uno/shared/types.hxx"
422755751fSHerbert Dürr #include "bridges/cpp_uno/shared/vtablefactory.hxx"
432755751fSHerbert Dürr 
442755751fSHerbert Dürr #include "abi.hxx"
452755751fSHerbert Dürr #include "share.hxx"
462755751fSHerbert Dürr 
472755751fSHerbert Dürr using namespace ::osl;
482755751fSHerbert Dürr using namespace ::rtl;
492755751fSHerbert Dürr using namespace ::com::sun::star::uno;
502755751fSHerbert Dürr 
512755751fSHerbert Dürr //==================================================================================================
522755751fSHerbert Dürr 
532755751fSHerbert Dürr // Perform the UNO call
542755751fSHerbert Dürr //
552755751fSHerbert Dürr // We must convert the paramaters stored in gpreg, fpreg and ovrflw to UNO
562755751fSHerbert Dürr // arguments and call pThis->getUnoI()->pDispatcher.
572755751fSHerbert Dürr //
582755751fSHerbert Dürr // gpreg:  [ret *], this, [gpr params]
592755751fSHerbert Dürr // fpreg:  [fpr params]
602755751fSHerbert Dürr // ovrflw: [gpr or fpr params (properly aligned)]
612755751fSHerbert Dürr //
622755751fSHerbert Dürr // [ret *] is present when we are returning a structure bigger than 16 bytes
632755751fSHerbert Dürr // Simple types are returned in rax, rdx (int), or xmm0, xmm1 (fp).
642755751fSHerbert Dürr // Similarly structures <= 16 bytes are in rax, rdx, xmm0, xmm1 as necessary.
cpp2uno_call(bridges::cpp_uno::shared::CppInterfaceProxy * pThis,const typelib_TypeDescription * pMemberTypeDescr,typelib_TypeDescriptionReference * pReturnTypeRef,sal_Int32 nParams,typelib_MethodParameter * pParams,void ** gpreg,void ** fpreg,void ** ovrflw,sal_uInt64 * pRegisterReturn)652755751fSHerbert Dürr static typelib_TypeClass cpp2uno_call(
662755751fSHerbert Dürr 	bridges::cpp_uno::shared::CppInterfaceProxy * pThis,
672755751fSHerbert Dürr 	const typelib_TypeDescription * pMemberTypeDescr,
682755751fSHerbert Dürr 	typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return
692755751fSHerbert Dürr 	sal_Int32 nParams, typelib_MethodParameter * pParams,
702755751fSHerbert Dürr 	void ** gpreg, void ** fpreg, void ** ovrflw,
712755751fSHerbert Dürr 	sal_uInt64 * pRegisterReturn /* space for register return */ )
722755751fSHerbert Dürr {
732755751fSHerbert Dürr 	unsigned int nr_gpr = 0; //number of gpr registers used
742755751fSHerbert Dürr 	unsigned int nr_fpr = 0; //number of fpr registers used
752755751fSHerbert Dürr 
762755751fSHerbert Dürr 	// return
772755751fSHerbert Dürr 	typelib_TypeDescription * pReturnTypeDescr = 0;
782755751fSHerbert Dürr 	if (pReturnTypeRef)
792755751fSHerbert Dürr 		TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
802755751fSHerbert Dürr 
812755751fSHerbert Dürr 	void * pUnoReturn = 0;
822755751fSHerbert Dürr 	void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
832755751fSHerbert Dürr 
842755751fSHerbert Dürr 	if ( pReturnTypeDescr )
852755751fSHerbert Dürr 	{
862755751fSHerbert Dürr 		if ( x86_64::return_in_hidden_param( pReturnTypeRef ) )
872755751fSHerbert Dürr 		{
882755751fSHerbert Dürr 			pCppReturn = *gpreg++;
892755751fSHerbert Dürr 			nr_gpr++;
902755751fSHerbert Dürr 
912755751fSHerbert Dürr 			pUnoReturn = ( bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
922755751fSHerbert Dürr 						   ? alloca( pReturnTypeDescr->nSize )
932755751fSHerbert Dürr 						   : pCppReturn ); // direct way
942755751fSHerbert Dürr 		}
952755751fSHerbert Dürr 		else
962755751fSHerbert Dürr 			pUnoReturn = pRegisterReturn; // direct way for simple types
972755751fSHerbert Dürr 	}
982755751fSHerbert Dürr 
992755751fSHerbert Dürr 	// pop this
1002755751fSHerbert Dürr 	gpreg++;
1012755751fSHerbert Dürr 	nr_gpr++;
1022755751fSHerbert Dürr 
1032755751fSHerbert Dürr 	// stack space
1042755751fSHerbert Dürr 	// parameters
105*67a794bcSJim Jagielski 	void ** pUnoArgs = reinterpret_cast<void **>(alloca( 4 * sizeof(void *) * nParams ));
1062755751fSHerbert Dürr 	void ** pCppArgs = pUnoArgs + nParams;
1072755751fSHerbert Dürr 	// indizes of values this have to be converted (interface conversion cpp<=>uno)
108*67a794bcSJim Jagielski 	sal_Int32 * pTempIndizes = reinterpret_cast<sal_Int32 *>(pUnoArgs + (2 * nParams));
1092755751fSHerbert Dürr 	// type descriptions for reconversions
110*67a794bcSJim Jagielski 	typelib_TypeDescription ** ppTempParamTypeDescr = reinterpret_cast<typelib_TypeDescription **>(pUnoArgs + (3 * nParams));
1112755751fSHerbert Dürr 
1122755751fSHerbert Dürr 	sal_Int32 nTempIndizes = 0;
1132755751fSHerbert Dürr 
1142755751fSHerbert Dürr 	for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
1152755751fSHerbert Dürr 	{
1162755751fSHerbert Dürr 		const typelib_MethodParameter & rParam = pParams[nPos];
1172755751fSHerbert Dürr 
1182755751fSHerbert Dürr 		int nUsedGPR = 0;
1192755751fSHerbert Dürr 		int nUsedSSE = 0;
120*67a794bcSJim Jagielski 		bool bFitsRegisters = x86_64::examine_argument( rParam.pTypeRef, false, nUsedGPR, nUsedSSE );
1212755751fSHerbert Dürr 		if ( !rParam.bOut && bridges::cpp_uno::shared::isSimpleType( rParam.pTypeRef ) ) // value
1222755751fSHerbert Dürr 		{
1232755751fSHerbert Dürr 			// Simple types must fit exactly one register on x86_64
1242755751fSHerbert Dürr 			OSL_ASSERT( bFitsRegisters && ( ( nUsedSSE == 1 && nUsedGPR == 0 ) || ( nUsedSSE == 0 && nUsedGPR == 1 ) ) );
1252755751fSHerbert Dürr 
1262755751fSHerbert Dürr 			if ( nUsedSSE == 1 )
1272755751fSHerbert Dürr 			{
1282755751fSHerbert Dürr 				if ( nr_fpr < x86_64::MAX_SSE_REGS )
1292755751fSHerbert Dürr 				{
1302755751fSHerbert Dürr 					pCppArgs[nPos] = pUnoArgs[nPos] = fpreg++;
1312755751fSHerbert Dürr 					nr_fpr++;
1322755751fSHerbert Dürr 				}
1332755751fSHerbert Dürr 				else
1342755751fSHerbert Dürr 					pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw++;
1352755751fSHerbert Dürr 			}
1362755751fSHerbert Dürr 			else if ( nUsedGPR == 1 )
1372755751fSHerbert Dürr 			{
1382755751fSHerbert Dürr 				if ( nr_gpr < x86_64::MAX_GPR_REGS )
1392755751fSHerbert Dürr 				{
1402755751fSHerbert Dürr 					pCppArgs[nPos] = pUnoArgs[nPos] = gpreg++;
1412755751fSHerbert Dürr 					nr_gpr++;
1422755751fSHerbert Dürr 				}
1432755751fSHerbert Dürr 				else
1442755751fSHerbert Dürr 					pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw++;
1452755751fSHerbert Dürr 			}
1462755751fSHerbert Dürr 		}
1472755751fSHerbert Dürr 		else // struct <= 16 bytes || ptr to complex value || ref
1482755751fSHerbert Dürr 		{
1492755751fSHerbert Dürr 			typelib_TypeDescription * pParamTypeDescr = 0;
1502755751fSHerbert Dürr 			TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
1512755751fSHerbert Dürr 
1522755751fSHerbert Dürr 			void *pCppStack;
1532755751fSHerbert Dürr 			if ( nr_gpr < x86_64::MAX_GPR_REGS )
1542755751fSHerbert Dürr 			{
1552755751fSHerbert Dürr 				pCppArgs[nPos] = pCppStack = *gpreg++;
1562755751fSHerbert Dürr 				nr_gpr++;
1572755751fSHerbert Dürr 			}
1582755751fSHerbert Dürr 			else
1592755751fSHerbert Dürr 				pCppArgs[nPos] = pCppStack = *ovrflw++;
1602755751fSHerbert Dürr 
1612755751fSHerbert Dürr 			if (! rParam.bIn) // is pure out
1622755751fSHerbert Dürr 			{
1632755751fSHerbert Dürr 				// uno out is unconstructed mem!
1642755751fSHerbert Dürr 				pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
1652755751fSHerbert Dürr 				pTempIndizes[nTempIndizes] = nPos;
1662755751fSHerbert Dürr 				// will be released at reconversion
1672755751fSHerbert Dürr 				ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
1682755751fSHerbert Dürr 			}
1692755751fSHerbert Dürr 			else if ( bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ) ) // is in/inout
1702755751fSHerbert Dürr 			{
1712755751fSHerbert Dürr 				uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
1722755751fSHerbert Dürr 										pCppStack, pParamTypeDescr,
1732755751fSHerbert Dürr 										pThis->getBridge()->getCpp2Uno() );
1742755751fSHerbert Dürr 				pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
1752755751fSHerbert Dürr 				// will be released at reconversion
1762755751fSHerbert Dürr 				ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
1772755751fSHerbert Dürr 			}
1782755751fSHerbert Dürr 			else // direct way
1792755751fSHerbert Dürr 			{
1802755751fSHerbert Dürr 				pUnoArgs[nPos] = pCppStack;
1812755751fSHerbert Dürr 				// no longer needed
1822755751fSHerbert Dürr 				TYPELIB_DANGER_RELEASE( pParamTypeDescr );
1832755751fSHerbert Dürr 			}
1842755751fSHerbert Dürr 		}
1852755751fSHerbert Dürr 	}
1862755751fSHerbert Dürr 
1872755751fSHerbert Dürr 	// ExceptionHolder
1882755751fSHerbert Dürr 	uno_Any aUnoExc; // Any will be constructed by callee
1892755751fSHerbert Dürr 	uno_Any * pUnoExc = &aUnoExc;
1902755751fSHerbert Dürr 
1912755751fSHerbert Dürr 	// invoke uno dispatch call
1922755751fSHerbert Dürr 	(*pThis->getUnoI()->pDispatcher)( pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
1932755751fSHerbert Dürr 
194*67a794bcSJim Jagielski 	// in case an exception occurred...
1952755751fSHerbert Dürr 	if ( pUnoExc )
1962755751fSHerbert Dürr 	{
1972755751fSHerbert Dürr 		// destruct temporary in/inout params
1982755751fSHerbert Dürr 		for ( ; nTempIndizes--; )
1992755751fSHerbert Dürr 		{
2002755751fSHerbert Dürr 			sal_Int32 nIndex = pTempIndizes[nTempIndizes];
2012755751fSHerbert Dürr 
2022755751fSHerbert Dürr 			if (pParams[nIndex].bIn) // is in/inout => was constructed
2032755751fSHerbert Dürr 				uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], 0 );
2042755751fSHerbert Dürr 			TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
2052755751fSHerbert Dürr 		}
2062755751fSHerbert Dürr 		if (pReturnTypeDescr)
2072755751fSHerbert Dürr 			TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
2082755751fSHerbert Dürr 
2092755751fSHerbert Dürr 		CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc, pThis->getBridge()->getUno2Cpp() ); // has to destruct the any
2102755751fSHerbert Dürr 		// is here for dummy
2112755751fSHerbert Dürr 		return typelib_TypeClass_VOID;
2122755751fSHerbert Dürr 	}
213*67a794bcSJim Jagielski 	else // else no exception occurred...
2142755751fSHerbert Dürr 	{
2152755751fSHerbert Dürr 		// temporary params
2162755751fSHerbert Dürr 		for ( ; nTempIndizes--; )
2172755751fSHerbert Dürr 		{
2182755751fSHerbert Dürr 			sal_Int32 nIndex = pTempIndizes[nTempIndizes];
2192755751fSHerbert Dürr 			typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
2202755751fSHerbert Dürr 
2212755751fSHerbert Dürr 			if ( pParams[nIndex].bOut ) // inout/out
2222755751fSHerbert Dürr 			{
2232755751fSHerbert Dürr 				// convert and assign
2242755751fSHerbert Dürr 				uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
2252755751fSHerbert Dürr 				uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
2262755751fSHerbert Dürr 										pThis->getBridge()->getUno2Cpp() );
2272755751fSHerbert Dürr 			}
2282755751fSHerbert Dürr 			// destroy temp uno param
2292755751fSHerbert Dürr 			uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
2302755751fSHerbert Dürr 
2312755751fSHerbert Dürr 			TYPELIB_DANGER_RELEASE( pParamTypeDescr );
2322755751fSHerbert Dürr 		}
2332755751fSHerbert Dürr 		// return
2342755751fSHerbert Dürr 		if ( pCppReturn ) // has complex return
2352755751fSHerbert Dürr 		{
2362755751fSHerbert Dürr 			if ( pUnoReturn != pCppReturn ) // needs reconversion
2372755751fSHerbert Dürr 			{
2382755751fSHerbert Dürr 				uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
2392755751fSHerbert Dürr 										pThis->getBridge()->getUno2Cpp() );
2402755751fSHerbert Dürr 				// destroy temp uno return
2412755751fSHerbert Dürr 				uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
2422755751fSHerbert Dürr 			}
2432755751fSHerbert Dürr 			// complex return ptr is set to return reg
244*67a794bcSJim Jagielski 			*reinterpret_cast<void **>(pRegisterReturn) = pCppReturn;
2452755751fSHerbert Dürr 		}
2462755751fSHerbert Dürr 		if ( pReturnTypeDescr )
2472755751fSHerbert Dürr 		{
2482755751fSHerbert Dürr 			typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
2492755751fSHerbert Dürr 			TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
2502755751fSHerbert Dürr 			return eRet;
2512755751fSHerbert Dürr 		}
2522755751fSHerbert Dürr 		else
2532755751fSHerbert Dürr 			return typelib_TypeClass_VOID;
2542755751fSHerbert Dürr 	}
2552755751fSHerbert Dürr }
2562755751fSHerbert Dürr 
2572755751fSHerbert Dürr 
2582755751fSHerbert Dürr //==================================================================================================
cpp_vtable_call(sal_Int32 nFunctionIndex,sal_Int32 nVtableOffset,void ** gpreg,void ** fpreg,void ** ovrflw,sal_uInt64 * pRegisterReturn)2592755751fSHerbert Dürr extern "C" typelib_TypeClass cpp_vtable_call(
2602755751fSHerbert Dürr 	sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
2612755751fSHerbert Dürr 	void ** gpreg, void ** fpreg, void ** ovrflw,
2622755751fSHerbert Dürr 	sal_uInt64 * pRegisterReturn /* space for register return */ )
2632755751fSHerbert Dürr {
2642755751fSHerbert Dürr 	// gpreg:  [ret *], this, [other gpr params]
2652755751fSHerbert Dürr 	// fpreg:  [fpr params]
2662755751fSHerbert Dürr 	// ovrflw: [gpr or fpr params (properly aligned)]
2672755751fSHerbert Dürr 	void * pThis;
2682755751fSHerbert Dürr 	if ( nFunctionIndex & 0x80000000 )
2692755751fSHerbert Dürr 	{
2702755751fSHerbert Dürr 		nFunctionIndex &= 0x7fffffff;
2712755751fSHerbert Dürr 		pThis = gpreg[1];
2722755751fSHerbert Dürr 	}
2732755751fSHerbert Dürr 	else
2742755751fSHerbert Dürr 	{
2752755751fSHerbert Dürr 		pThis = gpreg[0];
2762755751fSHerbert Dürr 	}
2772755751fSHerbert Dürr 	pThis = static_cast<char *>( pThis ) - nVtableOffset;
2782755751fSHerbert Dürr 
2792755751fSHerbert Dürr 	bridges::cpp_uno::shared::CppInterfaceProxy * pCppI =
2802755751fSHerbert Dürr 		bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( pThis );
2812755751fSHerbert Dürr 
2822755751fSHerbert Dürr 	typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
2832755751fSHerbert Dürr 
2842755751fSHerbert Dürr 	OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!\n" );
2852755751fSHerbert Dürr 	if ( nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex )
2862755751fSHerbert Dürr 	{
2872755751fSHerbert Dürr 		throw RuntimeException( OUString::createFromAscii("illegal vtable index!"),
2882755751fSHerbert Dürr 								reinterpret_cast<XInterface *>( pCppI ) );
2892755751fSHerbert Dürr 	}
2902755751fSHerbert Dürr 
2912755751fSHerbert Dürr 	// determine called method
2922755751fSHerbert Dürr 	sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
2932755751fSHerbert Dürr 	OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!\n" );
2942755751fSHerbert Dürr 
2952755751fSHerbert Dürr 	TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
2962755751fSHerbert Dürr 
2972755751fSHerbert Dürr 	typelib_TypeClass eRet;
2982755751fSHerbert Dürr 	switch ( aMemberDescr.get()->eTypeClass )
2992755751fSHerbert Dürr 	{
3002755751fSHerbert Dürr 		case typelib_TypeClass_INTERFACE_ATTRIBUTE:
3012755751fSHerbert Dürr 		{
3022755751fSHerbert Dürr 			typelib_TypeDescriptionReference *pAttrTypeRef =
3032755751fSHerbert Dürr 				reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( aMemberDescr.get() )->pAttributeTypeRef;
3042755751fSHerbert Dürr 
3052755751fSHerbert Dürr 			if ( pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex )
3062755751fSHerbert Dürr 			{
3072755751fSHerbert Dürr 				// is GET method
3082755751fSHerbert Dürr 				eRet = cpp2uno_call( pCppI, aMemberDescr.get(), pAttrTypeRef,
3092755751fSHerbert Dürr 						0, 0, // no params
3102755751fSHerbert Dürr 						gpreg, fpreg, ovrflw, pRegisterReturn );
3112755751fSHerbert Dürr 			}
3122755751fSHerbert Dürr 			else
3132755751fSHerbert Dürr 			{
3142755751fSHerbert Dürr 				// is SET method
3152755751fSHerbert Dürr 				typelib_MethodParameter aParam;
3162755751fSHerbert Dürr 				aParam.pTypeRef = pAttrTypeRef;
3172755751fSHerbert Dürr 				aParam.bIn		= sal_True;
3182755751fSHerbert Dürr 				aParam.bOut		= sal_False;
3192755751fSHerbert Dürr 
3202755751fSHerbert Dürr 				eRet = cpp2uno_call( pCppI, aMemberDescr.get(),
3212755751fSHerbert Dürr 						0, // indicates void return
3222755751fSHerbert Dürr 						1, &aParam,
3232755751fSHerbert Dürr 						gpreg, fpreg, ovrflw, pRegisterReturn );
3242755751fSHerbert Dürr 			}
3252755751fSHerbert Dürr 			break;
3262755751fSHerbert Dürr 		}
3272755751fSHerbert Dürr 		case typelib_TypeClass_INTERFACE_METHOD:
3282755751fSHerbert Dürr 		{
3292755751fSHerbert Dürr 			// is METHOD
3302755751fSHerbert Dürr 			switch ( nFunctionIndex )
3312755751fSHerbert Dürr 			{
3322755751fSHerbert Dürr 				case 1: // acquire()
3332755751fSHerbert Dürr 					pCppI->acquireProxy(); // non virtual call!
3342755751fSHerbert Dürr 					eRet = typelib_TypeClass_VOID;
3352755751fSHerbert Dürr 					break;
3362755751fSHerbert Dürr 				case 2: // release()
3372755751fSHerbert Dürr 					pCppI->releaseProxy(); // non virtual call!
3382755751fSHerbert Dürr 					eRet = typelib_TypeClass_VOID;
3392755751fSHerbert Dürr 					break;
3402755751fSHerbert Dürr 				case 0: // queryInterface() opt
3412755751fSHerbert Dürr 				{
3422755751fSHerbert Dürr 					typelib_TypeDescription * pTD = 0;
3432755751fSHerbert Dürr 					TYPELIB_DANGER_GET( &pTD, reinterpret_cast<Type *>( gpreg[2] )->getTypeLibType() );
3442755751fSHerbert Dürr 					if ( pTD )
3452755751fSHerbert Dürr 					{
3462755751fSHerbert Dürr 						XInterface * pInterface = 0;
3472755751fSHerbert Dürr 						(*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)
3482755751fSHerbert Dürr 							( pCppI->getBridge()->getCppEnv(),
349*67a794bcSJim Jagielski 							  reinterpret_cast<void **>(&pInterface),
3502755751fSHerbert Dürr 							  pCppI->getOid().pData,
3512755751fSHerbert Dürr 							  reinterpret_cast<typelib_InterfaceTypeDescription *>( pTD ) );
3522755751fSHerbert Dürr 
3532755751fSHerbert Dürr 						if ( pInterface )
3542755751fSHerbert Dürr 						{
3552755751fSHerbert Dürr 							::uno_any_construct( reinterpret_cast<uno_Any *>( gpreg[0] ),
3562755751fSHerbert Dürr 												 &pInterface, pTD, cpp_acquire );
3572755751fSHerbert Dürr 
3582755751fSHerbert Dürr 							pInterface->release();
3592755751fSHerbert Dürr 							TYPELIB_DANGER_RELEASE( pTD );
3602755751fSHerbert Dürr 
3612755751fSHerbert Dürr 							reinterpret_cast<void **>( pRegisterReturn )[0] = gpreg[0];
3622755751fSHerbert Dürr 							eRet = typelib_TypeClass_ANY;
3632755751fSHerbert Dürr 							break;
3642755751fSHerbert Dürr 						}
3652755751fSHerbert Dürr 						TYPELIB_DANGER_RELEASE( pTD );
3662755751fSHerbert Dürr 					}
3672755751fSHerbert Dürr 				} // else perform queryInterface()
3682755751fSHerbert Dürr 				default:
3692755751fSHerbert Dürr 				{
3702755751fSHerbert Dürr 					typelib_InterfaceMethodTypeDescription *pMethodTD =
3712755751fSHerbert Dürr 						reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( aMemberDescr.get() );
3722755751fSHerbert Dürr 
3732755751fSHerbert Dürr 					eRet = cpp2uno_call( pCppI, aMemberDescr.get(),
3742755751fSHerbert Dürr 										 pMethodTD->pReturnTypeRef,
3752755751fSHerbert Dürr 										 pMethodTD->nParams,
3762755751fSHerbert Dürr 										 pMethodTD->pParams,
3772755751fSHerbert Dürr 										 gpreg, fpreg, ovrflw, pRegisterReturn );
3782755751fSHerbert Dürr 				}
3792755751fSHerbert Dürr 			}
3802755751fSHerbert Dürr 			break;
3812755751fSHerbert Dürr 		}
3822755751fSHerbert Dürr 		default:
3832755751fSHerbert Dürr 		{
3842755751fSHerbert Dürr 			throw RuntimeException( OUString::createFromAscii("no member description found!"),
3852755751fSHerbert Dürr 									reinterpret_cast<XInterface *>( pCppI ) );
3862755751fSHerbert Dürr 			// is here for dummy
3872755751fSHerbert Dürr 			eRet = typelib_TypeClass_VOID;
3882755751fSHerbert Dürr 		}
3892755751fSHerbert Dürr 	}
3902755751fSHerbert Dürr 
3912755751fSHerbert Dürr 	return eRet;
3922755751fSHerbert Dürr }
3932755751fSHerbert Dürr 
3942755751fSHerbert Dürr //==================================================================================================
privateSnippetExecutor(void)3951466499aSHerbert Dürr extern "C" void privateSnippetExecutor( void )
3961466499aSHerbert Dürr {
397*67a794bcSJim Jagielski 	asm volatile (
398*67a794bcSJim Jagielski 		"	subq	$160, %rsp\n"
399*67a794bcSJim Jagielski 		"	movq	%r10, -152(%rbp)\n"		// Save (nVtableOffset << 32) + nFunctionIndex
400*67a794bcSJim Jagielski 
401*67a794bcSJim Jagielski 		"	movq	%rdi, -112(%rbp)\n"		// Save GP registers
402*67a794bcSJim Jagielski 		"	movq	%rsi, -104(%rbp)\n"
403*67a794bcSJim Jagielski 		"	movq	%rdx, -96(%rbp)\n"
404*67a794bcSJim Jagielski 		"	movq	%rcx, -88(%rbp)\n"
405*67a794bcSJim Jagielski 		"	movq	%r8 , -80(%rbp)\n"
406*67a794bcSJim Jagielski 		"	movq	%r9 , -72(%rbp)\n"
407*67a794bcSJim Jagielski 
408*67a794bcSJim Jagielski 		"	movsd	%xmm0, -64(%rbp)\n"		// Save FP registers
409*67a794bcSJim Jagielski 		"	movsd	%xmm1, -56(%rbp)\n"
410*67a794bcSJim Jagielski 		"	movsd	%xmm2, -48(%rbp)\n"
411*67a794bcSJim Jagielski 		"	movsd	%xmm3, -40(%rbp)\n"
412*67a794bcSJim Jagielski 		"	movsd	%xmm4, -32(%rbp)\n"
413*67a794bcSJim Jagielski 		"	movsd	%xmm5, -24(%rbp)\n"
414*67a794bcSJim Jagielski 		"	movsd	%xmm6, -16(%rbp)\n"
415*67a794bcSJim Jagielski 		"	movsd	%xmm7, -8(%rbp)\n"
416*67a794bcSJim Jagielski 
417*67a794bcSJim Jagielski 		"	leaq	-144(%rbp), %r9\n"		// 6th param: sal_uInt64* pRegisterReturn
418*67a794bcSJim Jagielski 		"	leaq	16(%rbp),   %r8\n"		// 5rd param: void** ovrflw
419*67a794bcSJim Jagielski 		"	leaq	-64(%rbp),  %rcx\n"		// 4th param: void** fpreg
420*67a794bcSJim Jagielski 		"	leaq	-112(%rbp), %rdx\n"		// 3rd param: void** gpreg
421*67a794bcSJim Jagielski 		"	movl	-148(%rbp), %esi\n"		// 2nd param: sal_int32 nVtableOffset
422*67a794bcSJim Jagielski 		"	movl	-152(%rbp), %edi\n"		// 1st param: sal_int32 nFunctionIndex
423*67a794bcSJim Jagielski 
424*67a794bcSJim Jagielski 		"	call	_cpp_vtable_call\n"
425*67a794bcSJim Jagielski 
426*67a794bcSJim Jagielski 		"	cmp	$10, %rax\n"				// typelib_TypeClass_FLOAT
427*67a794bcSJim Jagielski 		"	je	.Lfloat\n"
428*67a794bcSJim Jagielski 		"	cmp	$11, %rax\n"				// typelib_TypeClass_DOUBLE
429*67a794bcSJim Jagielski 		"	je	.Lfloat\n"
430*67a794bcSJim Jagielski 
431*67a794bcSJim Jagielski 		"	movq	-144(%rbp), %rax\n"		// Return value (int case)
432*67a794bcSJim Jagielski 		"	movq	-136(%rbp), %rdx\n"		// Return value (int case)
433*67a794bcSJim Jagielski 		"	movq	-144(%rbp), %xmm0\n"	// Return value (int case)
434*67a794bcSJim Jagielski 		"	movq	-136(%rbp), %xmm1\n"	// Return value (int case)
435*67a794bcSJim Jagielski 		"	jmp	.Lfinish\n"
436*67a794bcSJim Jagielski 		".Lfloat:\n"
437*67a794bcSJim Jagielski 		"	movlpd	-144(%rbp), %xmm0\n"		// Return value (float/double case)
438*67a794bcSJim Jagielski 		".Lfinish:\n"
439*67a794bcSJim Jagielski 		"	addq	$160, %rsp\n"
440*67a794bcSJim Jagielski 	);
4411466499aSHerbert Dürr }
442*67a794bcSJim Jagielski const int codeSnippetSize = 24;
4432755751fSHerbert Dürr 
4442755751fSHerbert Dürr // Generate a trampoline that redirects method calls to
4452755751fSHerbert Dürr // privateSnippetExecutor().
4462755751fSHerbert Dürr //
447*67a794bcSJim Jagielski // privateSnippetExecutor() saves all the registers that are used for
448*67a794bcSJim Jagielski // parameter passing on x86_64, and calls the cpp_vtable_call().
449*67a794bcSJim Jagielski // When it returns, privateSnippetExecutor() sets the return value.
450*67a794bcSJim Jagielski //
4512755751fSHerbert Dürr // Note: The code snippet we build here must not create a stack frame,
4522755751fSHerbert Dürr // otherwise the UNO exceptions stop working thanks to non-existing
4532755751fSHerbert Dürr // unwinding info.
codeSnippet(unsigned char * code,sal_Int32 nFunctionIndex,sal_Int32 nVtableOffset,bool bHasHiddenParam)4542755751fSHerbert Dürr unsigned char * codeSnippet( unsigned char * code,
4552755751fSHerbert Dürr         sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
4562755751fSHerbert Dürr         bool bHasHiddenParam ) SAL_THROW( () )
4572755751fSHerbert Dürr {
458*67a794bcSJim Jagielski 	sal_uInt64 nOffsetAndIndex = ( static_cast<sal_uInt64>( nVtableOffset ) << 32 ) | static_cast<sal_uInt64>( nFunctionIndex );
4592755751fSHerbert Dürr 
4602755751fSHerbert Dürr 	if ( bHasHiddenParam )
4612755751fSHerbert Dürr 		nOffsetAndIndex |= 0x80000000;
4622755751fSHerbert Dürr 
4632755751fSHerbert Dürr 	// movq $<nOffsetAndIndex>, %r10
464*67a794bcSJim Jagielski     *reinterpret_cast<sal_uInt16 *>( code ) = 0xba49;
465*67a794bcSJim Jagielski     *reinterpret_cast<sal_uInt64 *>( code + 2 ) = nOffsetAndIndex;
4662755751fSHerbert Dürr 
4672755751fSHerbert Dürr 	// movq $<address of the privateSnippetExecutor>, %r11
468*67a794bcSJim Jagielski     *reinterpret_cast<sal_uInt16 *>( code + 10 ) = 0xbb49;
469*67a794bcSJim Jagielski     *reinterpret_cast<sal_uInt64 *>( code + 12 ) = reinterpret_cast<sal_uInt64>( privateSnippetExecutor );
4702755751fSHerbert Dürr 
4712755751fSHerbert Dürr 	// jmpq *%r11
4722755751fSHerbert Dürr 	*reinterpret_cast<sal_uInt32 *>( code + 20 ) = 0x00e3ff49;
4732755751fSHerbert Dürr 
4742755751fSHerbert Dürr 	return code + codeSnippetSize;
4752755751fSHerbert Dürr }
4762755751fSHerbert Dürr 
4772755751fSHerbert Dürr //==================================================================================================
4782755751fSHerbert Dürr struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; };
4792755751fSHerbert Dürr 
4802755751fSHerbert Dürr bridges::cpp_uno::shared::VtableFactory::Slot *
mapBlockToVtable(void * block)4812755751fSHerbert Dürr bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
4822755751fSHerbert Dürr {
4832755751fSHerbert Dürr     return static_cast< Slot * >(block) + 2;
4842755751fSHerbert Dürr }
4852755751fSHerbert Dürr 
4862755751fSHerbert Dürr //==================================================================================================
getBlockSize(sal_Int32 slotCount)4872755751fSHerbert Dürr sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize(
4882755751fSHerbert Dürr     sal_Int32 slotCount)
4892755751fSHerbert Dürr {
4902755751fSHerbert Dürr     return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
4912755751fSHerbert Dürr }
4922755751fSHerbert Dürr 
4932755751fSHerbert Dürr //==================================================================================================
4942755751fSHerbert Dürr bridges::cpp_uno::shared::VtableFactory::Slot *
initializeBlock(void * block,sal_Int32 slotCount)4952755751fSHerbert Dürr bridges::cpp_uno::shared::VtableFactory::initializeBlock(
4962755751fSHerbert Dürr     void * block, sal_Int32 slotCount)
4972755751fSHerbert Dürr {
4982755751fSHerbert Dürr     Slot * slots = mapBlockToVtable(block);
4992755751fSHerbert Dürr     slots[-2].fn = 0;
5002755751fSHerbert Dürr     slots[-1].fn = 0;
5012755751fSHerbert Dürr     return slots + slotCount;
5022755751fSHerbert Dürr }
5032755751fSHerbert Dürr 
5042755751fSHerbert Dürr //==================================================================================================
5052755751fSHerbert Dürr 
addLocalFunctions(Slot ** slots,unsigned char * code,typelib_InterfaceTypeDescription const * type,sal_Int32 nFunctionOffset,sal_Int32 functionCount,sal_Int32 nVtableOffset)5062755751fSHerbert Dürr unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
5071466499aSHerbert Dürr 	Slot ** slots, unsigned char * code, /*sal_PtrDiff writetoexecdiff,*/
5082755751fSHerbert Dürr 	typelib_InterfaceTypeDescription const * type, sal_Int32 nFunctionOffset,
5092755751fSHerbert Dürr 	sal_Int32 functionCount, sal_Int32 nVtableOffset )
5102755751fSHerbert Dürr {
511*67a794bcSJim Jagielski 	const sal_PtrDiff writetoexecdiff = 0;
5122755751fSHerbert Dürr 	(*slots) -= functionCount;
5132755751fSHerbert Dürr 	Slot * s = *slots;
5142755751fSHerbert Dürr 	for ( sal_Int32 nPos = 0; nPos < type->nMembers; ++nPos )
5152755751fSHerbert Dürr 	{
5162755751fSHerbert Dürr 		typelib_TypeDescription * pTD = 0;
5172755751fSHerbert Dürr 
5182755751fSHerbert Dürr 		TYPELIB_DANGER_GET( &pTD, type->ppMembers[ nPos ] );
5192755751fSHerbert Dürr 		OSL_ASSERT( pTD );
5202755751fSHerbert Dürr 
5212755751fSHerbert Dürr 		if ( typelib_TypeClass_INTERFACE_ATTRIBUTE == pTD->eTypeClass )
5222755751fSHerbert Dürr 		{
5232755751fSHerbert Dürr 			typelib_InterfaceAttributeTypeDescription *pAttrTD =
5242755751fSHerbert Dürr 				reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( pTD );
5252755751fSHerbert Dürr 
5262755751fSHerbert Dürr 			// get method
5272755751fSHerbert Dürr 			(s++)->fn = code + writetoexecdiff;
5282755751fSHerbert Dürr 			code = codeSnippet( code, nFunctionOffset++, nVtableOffset,
5292755751fSHerbert Dürr 								x86_64::return_in_hidden_param( pAttrTD->pAttributeTypeRef ) );
5302755751fSHerbert Dürr 
5312755751fSHerbert Dürr 			if ( ! pAttrTD->bReadOnly )
5322755751fSHerbert Dürr 			{
5332755751fSHerbert Dürr 				// set method
5342755751fSHerbert Dürr 				(s++)->fn = code + writetoexecdiff;
5352755751fSHerbert Dürr 				code = codeSnippet( code, nFunctionOffset++, nVtableOffset, false );
5362755751fSHerbert Dürr 			}
5372755751fSHerbert Dürr 		}
5382755751fSHerbert Dürr 		else if ( typelib_TypeClass_INTERFACE_METHOD == pTD->eTypeClass )
5392755751fSHerbert Dürr 		{
5402755751fSHerbert Dürr 			typelib_InterfaceMethodTypeDescription *pMethodTD =
5412755751fSHerbert Dürr 				reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( pTD );
5422755751fSHerbert Dürr 
5432755751fSHerbert Dürr 			(s++)->fn = code + writetoexecdiff;
5442755751fSHerbert Dürr 			code = codeSnippet( code, nFunctionOffset++, nVtableOffset,
5452755751fSHerbert Dürr 								x86_64::return_in_hidden_param( pMethodTD->pReturnTypeRef ) );
5462755751fSHerbert Dürr 		}
5472755751fSHerbert Dürr 		else
5482755751fSHerbert Dürr 			OSL_ASSERT( false );
5492755751fSHerbert Dürr 
5502755751fSHerbert Dürr 		TYPELIB_DANGER_RELEASE( pTD );
5512755751fSHerbert Dürr 	}
5522755751fSHerbert Dürr 	return code;
5532755751fSHerbert Dürr }
5542755751fSHerbert Dürr 
5552755751fSHerbert Dürr //==================================================================================================
flushCode(unsigned char const *,unsigned char const *)5562755751fSHerbert Dürr void bridges::cpp_uno::shared::VtableFactory::flushCode(
5572755751fSHerbert Dürr 	unsigned char const *, unsigned char const * )
5582755751fSHerbert Dürr {
5592755751fSHerbert Dürr }
560