1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_bridges.hxx"
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <hash_map>
34 
35 #include <rtl/alloc.h>
36 #include <osl/mutex.hxx>
37 
38 #include <com/sun/star/uno/genfunc.hxx>
39 #include "com/sun/star/uno/RuntimeException.hpp"
40 #include <uno/data.h>
41 #include <typelib/typedescription.hxx>
42 
43 #include "bridges/cpp_uno/shared/bridge.hxx"
44 #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx"
45 #include "bridges/cpp_uno/shared/types.hxx"
46 #include "bridges/cpp_uno/shared/vtablefactory.hxx"
47 
48 #include "abi.hxx"
49 #include "share.hxx"
50 
51 using namespace ::osl;
52 using namespace ::rtl;
53 using namespace ::com::sun::star::uno;
54 
55 //==================================================================================================
56 
57 // Perform the UNO call
58 //
59 // We must convert the paramaters stored in gpreg, fpreg and ovrflw to UNO
60 // arguments and call pThis->getUnoI()->pDispatcher.
61 //
62 // gpreg:  [ret *], this, [gpr params]
63 // fpreg:  [fpr params]
64 // ovrflw: [gpr or fpr params (properly aligned)]
65 //
66 // [ret *] is present when we are returning a structure bigger than 16 bytes
67 // Simple types are returned in rax, rdx (int), or xmm0, xmm1 (fp).
68 // Similarly structures <= 16 bytes are in rax, rdx, xmm0, xmm1 as necessary.
69 static typelib_TypeClass cpp2uno_call(
70 	bridges::cpp_uno::shared::CppInterfaceProxy * pThis,
71 	const typelib_TypeDescription * pMemberTypeDescr,
72 	typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return
73 	sal_Int32 nParams, typelib_MethodParameter * pParams,
74 	void ** gpreg, void ** fpreg, void ** ovrflw,
75 	sal_uInt64 * pRegisterReturn /* space for register return */ )
76 {
77 	int nr_gpr = 0; //number of gpr registers used
78 	int nr_fpr = 0; //number of fpr regsiters used
79 
80 	// return
81 	typelib_TypeDescription * pReturnTypeDescr = 0;
82 	if (pReturnTypeRef)
83 		TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
84 
85 	void * pUnoReturn = 0;
86 	void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
87 
88 	if ( pReturnTypeDescr )
89 	{
90 		if ( x86_64::return_in_hidden_param( pReturnTypeRef ) )
91 		{
92 			pCppReturn = *gpreg++;
93 			nr_gpr++;
94 
95 			pUnoReturn = ( bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
96 						   ? alloca( pReturnTypeDescr->nSize )
97 						   : pCppReturn ); // direct way
98 		}
99 		else
100 			pUnoReturn = pRegisterReturn; // direct way for simple types
101 	}
102 
103 	// pop this
104 	gpreg++;
105 	nr_gpr++;
106 
107 	// stack space
108 	// parameters
109 	void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams );
110 	void ** pCppArgs = pUnoArgs + nParams;
111 	// indizes of values this have to be converted (interface conversion cpp<=>uno)
112 	sal_Int32 * pTempIndizes = (sal_Int32 *)(pUnoArgs + (2 * nParams));
113 	// type descriptions for reconversions
114 	typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams));
115 
116 	sal_Int32 nTempIndizes = 0;
117 
118 	for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
119 	{
120 		const typelib_MethodParameter & rParam = pParams[nPos];
121 		typelib_TypeDescription * pParamTypeDescr = 0;
122 		TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
123 
124 		int nUsedGPR = 0;
125 		int nUsedSSE = 0;
126 		bool bFitsRegisters = x86_64::examine_argument( rParam.pTypeRef, false, nUsedGPR, nUsedSSE );
127 		if ( !rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ) ) // value
128 		{
129 			// Simple types must fit exactly one register on x86_64
130 			OSL_ASSERT( bFitsRegisters && ( ( nUsedSSE == 1 && nUsedGPR == 0 ) || ( nUsedSSE == 0 && nUsedGPR == 1 ) ) );
131 
132 			if ( nUsedSSE == 1 )
133 			{
134 				if ( nr_fpr < x86_64::MAX_SSE_REGS )
135 				{
136 					pCppArgs[nPos] = pUnoArgs[nPos] = fpreg++;
137 					nr_fpr++;
138 				}
139 				else
140 					pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw++;
141 			}
142 			else if ( nUsedGPR == 1 )
143 			{
144 				if ( nr_gpr < x86_64::MAX_GPR_REGS )
145 				{
146 					pCppArgs[nPos] = pUnoArgs[nPos] = gpreg++;
147 					nr_gpr++;
148 				}
149 				else
150 					pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw++;
151 			}
152 
153 			// no longer needed
154 			TYPELIB_DANGER_RELEASE( pParamTypeDescr );
155 		}
156 		else // struct <= 16 bytes || ptr to complex value || ref
157 		{
158 			void *pCppStack;
159 			char pTmpStruct[16];
160 
161 			if ( bFitsRegisters && !rParam.bOut &&
162 				 ( pParamTypeDescr->eTypeClass == typelib_TypeClass_STRUCT ||
163 				   pParamTypeDescr->eTypeClass == typelib_TypeClass_EXCEPTION ) )
164 			{
165 				if ( ( nr_gpr + nUsedGPR <= x86_64::MAX_GPR_REGS ) && ( nr_fpr + nUsedSSE <= x86_64::MAX_SSE_REGS ) )
166 				{
167 					x86_64::fill_struct( rParam.pTypeRef, gpreg, fpreg, pTmpStruct );
168 #if OSL_DEBUG_LEVEL > 1
169 					fprintf( stderr, "nUsedGPR == %d, nUsedSSE == %d, pTmpStruct[0] == 0x%x, pTmpStruct[1] == 0x%x, **gpreg == 0x%lx\n",
170 							nUsedGPR, nUsedSSE, pTmpStruct[0], pTmpStruct[1], *(sal_uInt64*)*gpreg );
171 #endif
172 
173 					pCppArgs[nPos] = pCppStack = reinterpret_cast<void *>( pTmpStruct );
174 					gpreg += nUsedGPR;
175 					fpreg += nUsedSSE;
176 				}
177 				else
178 					pCppArgs[nPos] = pCppStack = *ovrflw++;
179 			}
180 			else if ( nr_gpr < x86_64::MAX_GPR_REGS )
181 			{
182 				pCppArgs[nPos] = pCppStack = *gpreg++;
183 				nr_gpr++;
184 			}
185 			else
186 				pCppArgs[nPos] = pCppStack = *ovrflw++;
187 
188 			if (! rParam.bIn) // is pure out
189 			{
190 				// uno out is unconstructed mem!
191 				pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
192 				pTempIndizes[nTempIndizes] = nPos;
193 				// will be released at reconversion
194 				ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
195 			}
196 			else if ( bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ) ) // is in/inout
197 			{
198 				uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
199 										pCppStack, pParamTypeDescr,
200 										pThis->getBridge()->getCpp2Uno() );
201 				pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
202 				// will be released at reconversion
203 				ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
204 			}
205 			else // direct way
206 			{
207 				pUnoArgs[nPos] = pCppStack;
208 				// no longer needed
209 				TYPELIB_DANGER_RELEASE( pParamTypeDescr );
210 			}
211 		}
212 	}
213 
214 	// ExceptionHolder
215 	uno_Any aUnoExc; // Any will be constructed by callee
216 	uno_Any * pUnoExc = &aUnoExc;
217 
218 	// invoke uno dispatch call
219 	(*pThis->getUnoI()->pDispatcher)( pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
220 
221 	// in case an exception occured...
222 	if ( pUnoExc )
223 	{
224 		// destruct temporary in/inout params
225 		for ( ; nTempIndizes--; )
226 		{
227 			sal_Int32 nIndex = pTempIndizes[nTempIndizes];
228 
229 			if (pParams[nIndex].bIn) // is in/inout => was constructed
230 				uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], 0 );
231 			TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
232 		}
233 		if (pReturnTypeDescr)
234 			TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
235 
236 		CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc, pThis->getBridge()->getUno2Cpp() ); // has to destruct the any
237 		// is here for dummy
238 		return typelib_TypeClass_VOID;
239 	}
240 	else // else no exception occured...
241 	{
242 		// temporary params
243 		for ( ; nTempIndizes--; )
244 		{
245 			sal_Int32 nIndex = pTempIndizes[nTempIndizes];
246 			typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
247 
248 			if ( pParams[nIndex].bOut ) // inout/out
249 			{
250 				// convert and assign
251 				uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
252 				uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
253 										pThis->getBridge()->getUno2Cpp() );
254 			}
255 			// destroy temp uno param
256 			uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
257 
258 			TYPELIB_DANGER_RELEASE( pParamTypeDescr );
259 		}
260 		// return
261 		if ( pCppReturn ) // has complex return
262 		{
263 			if ( pUnoReturn != pCppReturn ) // needs reconversion
264 			{
265 				uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
266 										pThis->getBridge()->getUno2Cpp() );
267 				// destroy temp uno return
268 				uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
269 			}
270 			// complex return ptr is set to return reg
271 			*(void **)pRegisterReturn = pCppReturn;
272 		}
273 		if ( pReturnTypeDescr )
274 		{
275 			typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
276 			TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
277 			return eRet;
278 		}
279 		else
280 			return typelib_TypeClass_VOID;
281 	}
282 }
283 
284 
285 //==================================================================================================
286 extern "C" typelib_TypeClass cpp_vtable_call(
287 	sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
288 	void ** gpreg, void ** fpreg, void ** ovrflw,
289 	sal_uInt64 * pRegisterReturn /* space for register return */ )
290 {
291 	// gpreg:  [ret *], this, [other gpr params]
292 	// fpreg:  [fpr params]
293 	// ovrflw: [gpr or fpr params (properly aligned)]
294 	void * pThis;
295 	if ( nFunctionIndex & 0x80000000 )
296 	{
297 		nFunctionIndex &= 0x7fffffff;
298 		pThis = gpreg[1];
299 	}
300 	else
301 	{
302 		pThis = gpreg[0];
303 	}
304 	pThis = static_cast<char *>( pThis ) - nVtableOffset;
305 
306 	bridges::cpp_uno::shared::CppInterfaceProxy * pCppI =
307 		bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( pThis );
308 
309 	typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
310 
311 	OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!\n" );
312 	if ( nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex )
313 	{
314 		throw RuntimeException( OUString::createFromAscii("illegal vtable index!"),
315 								reinterpret_cast<XInterface *>( pCppI ) );
316 	}
317 
318 	// determine called method
319 	sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
320 	OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!\n" );
321 
322 	TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
323 
324 	typelib_TypeClass eRet;
325 	switch ( aMemberDescr.get()->eTypeClass )
326 	{
327 		case typelib_TypeClass_INTERFACE_ATTRIBUTE:
328 		{
329 			typelib_TypeDescriptionReference *pAttrTypeRef =
330 				reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( aMemberDescr.get() )->pAttributeTypeRef;
331 
332 			if ( pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex )
333 			{
334 				// is GET method
335 				eRet = cpp2uno_call( pCppI, aMemberDescr.get(), pAttrTypeRef,
336 						0, 0, // no params
337 						gpreg, fpreg, ovrflw, pRegisterReturn );
338 			}
339 			else
340 			{
341 				// is SET method
342 				typelib_MethodParameter aParam;
343 				aParam.pTypeRef = pAttrTypeRef;
344 				aParam.bIn		= sal_True;
345 				aParam.bOut		= sal_False;
346 
347 				eRet = cpp2uno_call( pCppI, aMemberDescr.get(),
348 						0, // indicates void return
349 						1, &aParam,
350 						gpreg, fpreg, ovrflw, pRegisterReturn );
351 			}
352 			break;
353 		}
354 		case typelib_TypeClass_INTERFACE_METHOD:
355 		{
356 			// is METHOD
357 			switch ( nFunctionIndex )
358 			{
359 				case 1: // acquire()
360 					pCppI->acquireProxy(); // non virtual call!
361 					eRet = typelib_TypeClass_VOID;
362 					break;
363 				case 2: // release()
364 					pCppI->releaseProxy(); // non virtual call!
365 					eRet = typelib_TypeClass_VOID;
366 					break;
367 				case 0: // queryInterface() opt
368 				{
369 					typelib_TypeDescription * pTD = 0;
370 					TYPELIB_DANGER_GET( &pTD, reinterpret_cast<Type *>( gpreg[2] )->getTypeLibType() );
371 					if ( pTD )
372 					{
373 						XInterface * pInterface = 0;
374 						(*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)
375 							( pCppI->getBridge()->getCppEnv(),
376 							  (void **)&pInterface,
377 							  pCppI->getOid().pData,
378 							  reinterpret_cast<typelib_InterfaceTypeDescription *>( pTD ) );
379 
380 						if ( pInterface )
381 						{
382 							::uno_any_construct( reinterpret_cast<uno_Any *>( gpreg[0] ),
383 												 &pInterface, pTD, cpp_acquire );
384 
385 							pInterface->release();
386 							TYPELIB_DANGER_RELEASE( pTD );
387 
388 							reinterpret_cast<void **>( pRegisterReturn )[0] = gpreg[0];
389 							eRet = typelib_TypeClass_ANY;
390 							break;
391 						}
392 						TYPELIB_DANGER_RELEASE( pTD );
393 					}
394 				} // else perform queryInterface()
395 				default:
396 				{
397 					typelib_InterfaceMethodTypeDescription *pMethodTD =
398 						reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( aMemberDescr.get() );
399 
400 					eRet = cpp2uno_call( pCppI, aMemberDescr.get(),
401 										 pMethodTD->pReturnTypeRef,
402 										 pMethodTD->nParams,
403 										 pMethodTD->pParams,
404 										 gpreg, fpreg, ovrflw, pRegisterReturn );
405 				}
406 			}
407 			break;
408 		}
409 		default:
410 		{
411 			throw RuntimeException( OUString::createFromAscii("no member description found!"),
412 									reinterpret_cast<XInterface *>( pCppI ) );
413 			// is here for dummy
414 			eRet = typelib_TypeClass_VOID;
415 		}
416 	}
417 
418 	return eRet;
419 }
420 
421 //==================================================================================================
422 extern "C" void privateSnippetExecutor( ... );
423 
424 const int codeSnippetSize = 24;
425 
426 // Generate a trampoline that redirects method calls to
427 // privateSnippetExecutor().
428 //
429 // privateSnippetExecutor() saves all the registers that are used for
430 // parameter passing on x86_64, and calls the cpp_vtable_call().
431 // When it returns, privateSnippetExecutor() sets the return value.
432 //
433 // Note: The code snippet we build here must not create a stack frame,
434 // otherwise the UNO exceptions stop working thanks to non-existing
435 // unwinding info.
436 unsigned char * codeSnippet( unsigned char * code,
437         sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
438         bool bHasHiddenParam ) SAL_THROW( () )
439 {
440 	sal_uInt64 nOffsetAndIndex = ( ( (sal_uInt64) nVtableOffset ) << 32 ) | ( (sal_uInt64) nFunctionIndex );
441 
442 	if ( bHasHiddenParam )
443 		nOffsetAndIndex |= 0x80000000;
444 
445 	// movq $<nOffsetAndIndex>, %r10
446 	*reinterpret_cast<sal_uInt16 *>( code ) = 0xba49;
447 	*reinterpret_cast<sal_uInt64 *>( code + 2 ) = nOffsetAndIndex;
448 
449 	// movq $<address of the privateSnippetExecutor>, %r11
450 	*reinterpret_cast<sal_uInt16 *>( code + 10 ) = 0xbb49;
451 	*reinterpret_cast<sal_uInt64 *>( code + 12 ) = reinterpret_cast<sal_uInt64>( privateSnippetExecutor );
452 
453 	// jmpq *%r11
454 	*reinterpret_cast<sal_uInt32 *>( code + 20 ) = 0x00e3ff49;
455 
456 	return code + codeSnippetSize;
457 }
458 
459 //==================================================================================================
460 struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; };
461 
462 bridges::cpp_uno::shared::VtableFactory::Slot *
463 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
464 {
465     return static_cast< Slot * >(block) + 2;
466 }
467 
468 //==================================================================================================
469 sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize(
470     sal_Int32 slotCount)
471 {
472     return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
473 }
474 
475 //==================================================================================================
476 bridges::cpp_uno::shared::VtableFactory::Slot *
477 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
478     void * block, sal_Int32 slotCount)
479 {
480     Slot * slots = mapBlockToVtable(block);
481     slots[-2].fn = 0;
482     slots[-1].fn = 0;
483     return slots + slotCount;
484 }
485 
486 //==================================================================================================
487 
488 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
489 	Slot ** slots, unsigned char * code,
490 	typelib_InterfaceTypeDescription const * type, sal_Int32 nFunctionOffset,
491 	sal_Int32 functionCount, sal_Int32 nVtableOffset )
492 {
493 	(*slots) -= functionCount;
494 	Slot * s = *slots;
495 
496 	for ( sal_Int32 nPos = 0; nPos < type->nMembers; ++nPos )
497 	{
498 		typelib_TypeDescription * pTD = 0;
499 
500 		TYPELIB_DANGER_GET( &pTD, type->ppMembers[ nPos ] );
501 		OSL_ASSERT( pTD );
502 
503 		if ( typelib_TypeClass_INTERFACE_ATTRIBUTE == pTD->eTypeClass )
504 		{
505 			typelib_InterfaceAttributeTypeDescription *pAttrTD =
506 				reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( pTD );
507 
508 			// get method
509 			(s++)->fn = code;
510 			code = codeSnippet( code, nFunctionOffset++, nVtableOffset,
511 								x86_64::return_in_hidden_param( pAttrTD->pAttributeTypeRef ) );
512 
513 			if ( ! pAttrTD->bReadOnly )
514 			{
515 				// set method
516 				(s++)->fn = code;
517 				code = codeSnippet( code, nFunctionOffset++, nVtableOffset, false );
518 			}
519 		}
520 		else if ( typelib_TypeClass_INTERFACE_METHOD == pTD->eTypeClass )
521 		{
522 			typelib_InterfaceMethodTypeDescription *pMethodTD =
523 				reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( pTD );
524 
525 			(s++)->fn = code;
526 			code = codeSnippet( code, nFunctionOffset++, nVtableOffset,
527 								x86_64::return_in_hidden_param( pMethodTD->pReturnTypeRef ) );
528 		}
529 		else
530 			OSL_ASSERT( false );
531 
532 		TYPELIB_DANGER_RELEASE( pTD );
533 	}
534 	return code;
535 }
536 
537 //==================================================================================================
538 void bridges::cpp_uno::shared::VtableFactory::flushCode(
539 	unsigned char const *, unsigned char const * )
540 {
541 }
542