xref: /AOO41X/main/bridges/source/cpp_uno/gcc3_macosx_intel/cpp2uno.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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 <com/sun/star/uno/genfunc.hxx>
32 #include "com/sun/star/uno/RuntimeException.hpp"
33 #include "com/sun/star/uno/Sequence.hxx"
34 #include <uno/data.h>
35 #include <typelib/typedescription.hxx>
36 
37 #include "bridges/cpp_uno/shared/bridge.hxx"
38 #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx"
39 #include "bridges/cpp_uno/shared/types.hxx"
40 #include "bridges/cpp_uno/shared/vtablefactory.hxx"
41 
42 #include "share.hxx"
43 
44 #include "boost/static_assert.hpp"
45 #include <stdio.h>
46 
47 using namespace ::com::sun::star::uno;
48 
49 namespace
50 {
51 
52 //==================================================================================================
53 void cpp2uno_call(
54 	bridges::cpp_uno::shared::CppInterfaceProxy * pThis,
55 	const typelib_TypeDescription * pMemberTypeDescr,
56 	typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return
57 	sal_Int32 nParams, typelib_MethodParameter * pParams,
58 	void ** pCallStack,
59 	void * pReturnValue )
60 {
61 	// pCallStack: ret, [return ptr], this, params
62 	char * pCppStack = (char *)(pCallStack +1);
63 
64 	// return
65 	typelib_TypeDescription * pReturnTypeDescr = 0;
66 	if (pReturnTypeRef)
67 		TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
68 
69 	void * pUnoReturn = 0;
70 	void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
71 
72 	if (pReturnTypeDescr)
73 	{
74         // xxx todo: test PolyStructy<STRUCT<long>> foo()
75 		if (CPPU_CURRENT_NAMESPACE::isSimpleReturnType( pReturnTypeDescr ))
76 		{
77 			pUnoReturn = pReturnValue; // direct way for simple types
78 		}
79 		else // complex return via ptr (pCppReturn)
80 		{
81             pCppReturn = *(void **)pCppStack;
82             pCppStack += sizeof(void *);
83 			pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType(
84                               pReturnTypeDescr )
85 						  ? alloca( pReturnTypeDescr->nSize )
86 						  : pCppReturn); // direct way
87 		}
88 	}
89 	// pop this
90 	pCppStack += sizeof( void* );
91 
92 	// stack space
93 	OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" );
94 	// parameters
95 	void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams );
96 	void ** pCppArgs = pUnoArgs + nParams;
97 	// indizes of values this have to be converted (interface conversion cpp<=>uno)
98 	sal_Int32 * pTempIndizes = (sal_Int32 *)(pUnoArgs + (2 * nParams));
99 	// type descriptions for reconversions
100 	typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams));
101 
102 	sal_Int32 nTempIndizes   = 0;
103 
104 	for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
105 	{
106 		const typelib_MethodParameter & rParam = pParams[nPos];
107 		typelib_TypeDescription * pParamTypeDescr = 0;
108 		TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
109 
110 		if (!rParam.bOut
111             && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
112             // value
113 		{
114 			pCppArgs[nPos] = pCppStack;
115 			pUnoArgs[nPos] = pCppStack;
116 			switch (pParamTypeDescr->eTypeClass)
117 			{
118 			case typelib_TypeClass_HYPER:
119 			case typelib_TypeClass_UNSIGNED_HYPER:
120 			case typelib_TypeClass_DOUBLE:
121 				pCppStack += sizeof(sal_Int32); // extra long
122             default:
123                 break;
124 			}
125 			// no longer needed
126 			TYPELIB_DANGER_RELEASE( pParamTypeDescr );
127 		}
128 		else // ptr to complex value | ref
129 		{
130 			pCppArgs[nPos] = *(void **)pCppStack;
131 
132 			if (! rParam.bIn) // is pure out
133 			{
134 				// uno out is unconstructed mem!
135 				pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
136 				pTempIndizes[nTempIndizes] = nPos;
137 				// will be released at reconversion
138 				ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
139 			}
140 			// is in/inout
141 			else if (bridges::cpp_uno::shared::relatesToInterfaceType(
142                          pParamTypeDescr ))
143 			{
144 				uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
145 										*(void **)pCppStack, pParamTypeDescr,
146 										pThis->getBridge()->getCpp2Uno() );
147 				pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
148 				// will be released at reconversion
149 				ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
150 			}
151 			else // direct way
152 			{
153 				pUnoArgs[nPos] = *(void **)pCppStack;
154 				// no longer needed
155 				TYPELIB_DANGER_RELEASE( pParamTypeDescr );
156 			}
157 		}
158 		pCppStack += sizeof(sal_Int32); // standard parameter length
159 	}
160 
161 	// ExceptionHolder
162 	uno_Any aUnoExc; // Any will be constructed by callee
163 	uno_Any * pUnoExc = &aUnoExc;
164 
165 	// invoke uno dispatch call
166 	(*pThis->getUnoI()->pDispatcher)(
167         pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
168 
169 	// in case an exception occured...
170 	if (pUnoExc)
171 	{
172 		// destruct temporary in/inout params
173 		for ( ; nTempIndizes--; )
174 		{
175 			sal_Int32 nIndex = pTempIndizes[nTempIndizes];
176 
177 			if (pParams[nIndex].bIn) // is in/inout => was constructed
178 				uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], 0 );
179 			TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
180 		}
181 		if (pReturnTypeDescr)
182 			TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
183 
184 		CPPU_CURRENT_NAMESPACE::raiseException(
185             &aUnoExc, pThis->getBridge()->getUno2Cpp() );
186             // has to destruct the any
187 	}
188 	else // else no exception occured...
189 	{
190 		// temporary params
191 		for ( ; nTempIndizes--; )
192 		{
193 			sal_Int32 nIndex = pTempIndizes[nTempIndizes];
194 			typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
195 
196 			if (pParams[nIndex].bOut) // inout/out
197 			{
198 				// convert and assign
199 				uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
200 				uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
201 										pThis->getBridge()->getUno2Cpp() );
202 			}
203 			// destroy temp uno param
204 			uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
205 
206 			TYPELIB_DANGER_RELEASE( pParamTypeDescr );
207 		}
208 		// return
209 		if (pCppReturn) // has complex return
210 		{
211 			if (pUnoReturn != pCppReturn) // needs reconversion
212 			{
213 				uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
214 										pThis->getBridge()->getUno2Cpp() );
215 				// destroy temp uno return
216 				uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
217 			}
218             if (pReturnValue != pCppReturn) {
219                 // complex return ptr is set to eax if return value
220                 // is not transferred via eax[/edx]:
221                 *static_cast< void ** >(pReturnValue) = pCppReturn;
222             }
223 		}
224 		if (pReturnTypeDescr)
225 		{
226 			TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
227 		}
228 	}
229 }
230 
231 
232 //==================================================================================================
233 extern "C" void cpp_vtable_call(
234     int nFunctionIndex, int nVtableOffset, void** pCallStack,
235     void * pReturnValue )
236 {
237 	OSL_ENSURE( sizeof(sal_Int32)==sizeof(void *), "### unexpected!" );
238 
239 	// pCallStack: ret adr, [ret *], this, params
240     void * pThis;
241 	if( nFunctionIndex & 0x80000000 )
242 	{
243 		nFunctionIndex &= 0x7fffffff;
244         pThis = pCallStack[2];
245 	}
246 	else
247     {
248         pThis = pCallStack[1];
249     }
250     pThis = static_cast< char * >(pThis) - nVtableOffset;
251 	bridges::cpp_uno::shared::CppInterfaceProxy * pCppI
252         = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
253             pThis);
254 #if OSL_DEBUG_LEVEL > 1
255     fprintf( stderr, "%p %p %p pThis=%p, pCppI=%p, function index=%d, vtable offset=%d\n", pCallStack[0], pCallStack[1], pCallStack[2], pThis, pCppI, nFunctionIndex, nVtableOffset );
256 #endif
257 	typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
258 #if OSL_DEBUG_LEVEL > 1
259     fprintf( stderr, "name=%s\n", rtl::OUStringToOString(pTypeDescr->aBase.pTypeName, RTL_TEXTENCODING_UTF8).getStr() );
260 #endif
261 	OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!" );
262 	if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
263 	{
264 		throw RuntimeException(
265             rtl::OUString::createFromAscii("illegal vtable index!"),
266             (XInterface *)pThis );
267 	}
268 
269 	// determine called method
270 	sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
271 	OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!" );
272 
273 	TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
274 #if OSL_DEBUG_LEVEL > 1
275     fprintf(stderr, "calling %s\n", rtl::OUStringToOString(aMemberDescr.get()->pTypeName, RTL_TEXTENCODING_UTF8).getStr());
276 #endif
277 	switch (aMemberDescr.get()->eTypeClass)
278 	{
279 	case typelib_TypeClass_INTERFACE_ATTRIBUTE:
280 	{
281 		if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex)
282 		{
283 			// is GET method
284 			cpp2uno_call(
285 				pCppI, aMemberDescr.get(),
286 				((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef,
287 				0, 0, // no params
288 				pCallStack, pReturnValue );
289 		}
290 		else
291 		{
292 			// is SET method
293 			typelib_MethodParameter aParam;
294 			aParam.pTypeRef =
295 				((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef;
296 			aParam.bIn		= sal_True;
297 			aParam.bOut		= sal_False;
298 
299 			cpp2uno_call(
300 				pCppI, aMemberDescr.get(),
301 				0, // indicates void return
302 				1, &aParam,
303 				pCallStack, pReturnValue );
304 		}
305 		break;
306 	}
307 	case typelib_TypeClass_INTERFACE_METHOD:
308 	{
309 		// is METHOD
310 		switch (nFunctionIndex)
311 		{
312 		case 1: // acquire()
313 			pCppI->acquireProxy(); // non virtual call!
314 			break;
315 		case 2: // release()
316 			pCppI->releaseProxy(); // non virtual call!
317 			break;
318 		case 0: // queryInterface() opt
319 		{
320 			typelib_TypeDescription * pTD = 0;
321 			TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pCallStack[3] )->getTypeLibType() );
322 			if (pTD)
323 			{
324                 XInterface * pInterface = 0;
325                 (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
326                     pCppI->getBridge()->getCppEnv(),
327                     (void **)&pInterface, pCppI->getOid().pData,
328                     (typelib_InterfaceTypeDescription *)pTD );
329 
330                 if (pInterface)
331                 {
332                     ::uno_any_construct(
333                         reinterpret_cast< uno_Any * >( pCallStack[1] ),
334                         &pInterface, pTD, cpp_acquire );
335                     pInterface->release();
336                     TYPELIB_DANGER_RELEASE( pTD );
337                     *static_cast< void ** >(pReturnValue) = pCallStack[1];
338                     break;
339                 }
340                 TYPELIB_DANGER_RELEASE( pTD );
341             }
342 		} // else perform queryInterface()
343 		default:
344 			cpp2uno_call(
345 				pCppI, aMemberDescr.get(),
346 				((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef,
347 				((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams,
348 				((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams,
349 				pCallStack, pReturnValue );
350 		}
351 		break;
352 	}
353 	default:
354 	{
355 		throw RuntimeException(
356             rtl::OUString::createFromAscii("no member description found!"),
357             (XInterface *)pThis );
358 	}
359 	}
360 }
361 
362 //==================================================================================================
363 extern "C" void privateSnippetExecutorGeneral();
364 extern "C" void privateSnippetExecutorVoid();
365 extern "C" void privateSnippetExecutorHyper();
366 extern "C" void privateSnippetExecutorFloat();
367 extern "C" void privateSnippetExecutorDouble();
368 extern "C" void privateSnippetExecutorClass();
369 extern "C" typedef void (*PrivateSnippetExecutor)();
370 
371 int const codeSnippetSize = 16;
372 
373 unsigned char * codeSnippet(
374     unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset,
375     typelib_TypeDescriptionReference * pReturnTypeRef)
376 {
377     PrivateSnippetExecutor exec;
378     if (pReturnTypeRef == 0) {
379         exec = privateSnippetExecutorVoid;
380     }
381     else {
382         switch (pReturnTypeRef->eTypeClass) {
383         case typelib_TypeClass_VOID:
384             exec = privateSnippetExecutorVoid;
385             break;
386         case typelib_TypeClass_HYPER:
387         case typelib_TypeClass_UNSIGNED_HYPER:
388             exec = privateSnippetExecutorHyper;
389             break;
390         case typelib_TypeClass_FLOAT:
391             exec = privateSnippetExecutorFloat;
392             break;
393         case typelib_TypeClass_DOUBLE:
394             exec = privateSnippetExecutorDouble;
395             break;
396         case typelib_TypeClass_STRUCT:
397         case typelib_TypeClass_EXCEPTION: {
398             typelib_TypeDescription * pReturnTypeDescr = 0;
399             TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
400             bool const bSimpleReturnStruct =
401                 CPPU_CURRENT_NAMESPACE::isSimpleReturnType(pReturnTypeDescr);
402             sal_Int32 const nRetSize = pReturnTypeDescr->nSize;
403             TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
404             if (bSimpleReturnStruct && nRetSize <= 8) {
405                 exec = privateSnippetExecutorGeneral; // fills eax
406                 if (nRetSize > 4)
407                     exec = privateSnippetExecutorHyper; // fills eax/edx
408                 break;
409             }
410         }
411         case typelib_TypeClass_STRING:
412         case typelib_TypeClass_TYPE:
413         case typelib_TypeClass_SEQUENCE:
414         case typelib_TypeClass_INTERFACE:
415         case typelib_TypeClass_ANY:
416             functionIndex |= 0x80000000;
417             exec = privateSnippetExecutorClass;
418             break;
419         default:
420             exec = privateSnippetExecutorGeneral;
421             break;
422         }
423     }
424     unsigned char * p = code;
425     OSL_ASSERT(sizeof (sal_Int32) == 4);
426     // mov function_index, %eax:
427     *p++ = 0xB8;
428     *reinterpret_cast< sal_Int32 * >(p) = functionIndex;
429     p += sizeof (sal_Int32);
430     // mov vtable_offset, %edx:
431     *p++ = 0xBA;
432     *reinterpret_cast< sal_Int32 * >(p) = vtableOffset;
433     p += sizeof (sal_Int32);
434     // jmp privateSnippetExecutor:
435     *p++ = 0xE9;
436     *reinterpret_cast< sal_Int32 * >(p)
437         = ((unsigned char *) exec) - p - sizeof (sal_Int32);
438     p += sizeof (sal_Int32);
439     OSL_ASSERT(p - code <= codeSnippetSize);
440     return code + codeSnippetSize;
441 }
442 
443 }
444 
445 struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; };
446 
447 bridges::cpp_uno::shared::VtableFactory::Slot *
448 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
449 {
450     return static_cast< Slot * >(block) + 2;
451 }
452 
453 sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize(
454     sal_Int32 slotCount)
455 {
456     return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
457 }
458 
459 bridges::cpp_uno::shared::VtableFactory::Slot *
460 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
461     void * block, sal_Int32 slotCount)
462 {
463     Slot * slots = mapBlockToVtable(block);
464     slots[-2].fn = 0;
465     slots[-1].fn = 0;
466     return slots + slotCount;
467 }
468 
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)
473 {
474     (*slots) -= functionCount;
475     Slot * s = *slots;
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:
482             // Getter:
483             (s++)->fn = code;
484             code = codeSnippet(
485                 code, functionOffset++, vtableOffset,
486                 reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >(
487                     member)->pAttributeTypeRef);
488             // Setter:
489             if (!reinterpret_cast<
490                 typelib_InterfaceAttributeTypeDescription * >(
491                     member)->bReadOnly)
492             {
493                 (s++)->fn = code;
494                 code = codeSnippet(
495                     code, functionOffset++, vtableOffset,
496                     0 /* indicates VOID */);
497             }
498             break;
499 
500         case typelib_TypeClass_INTERFACE_METHOD:
501             (s++)->fn = code;
502             code = codeSnippet(
503                 code, functionOffset++, vtableOffset,
504                 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
505                     member)->pReturnTypeRef);
506             break;
507 
508         default:
509             OSL_ASSERT(false);
510             break;
511         }
512         TYPELIB_DANGER_RELEASE(member);
513     }
514     return code;
515 }
516 
517 void bridges::cpp_uno::shared::VtableFactory::flushCode(
518     unsigned char const *, unsigned char const *)
519 {}
520