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 #include <malloc.h>
29 
30 #include <com/sun/star/uno/genfunc.hxx>
31 #include <uno/data.h>
32 
33 #include "bridges/cpp_uno/shared/bridge.hxx"
34 #include "bridges/cpp_uno/shared/types.hxx"
35 #include "bridges/cpp_uno/shared/unointerfaceproxy.hxx"
36 #include "bridges/cpp_uno/shared/vtables.hxx"
37 
38 #include "share.hxx"
39 
40 //#define BRDEBUG
41 #ifdef BRDEBUG
42 #include <stdio.h>
43 #endif
44 
45 
46 using namespace ::rtl;
47 using namespace ::com::sun::star::uno;
48 
49 namespace
50 {
51 
52 
53   //==================================================================================================
54   static void callVirtualMethod(
55 	  void * pAdjustedThisPtr,
56 	  sal_Int32 nVtableIndex,
57 	  void * pRegisterReturn,
58 	  typelib_TypeClass eReturnType,
59 	  char * pPT,
60 	  sal_Int32 * pStackLongs,
61 	  sal_Int32 /*nStackLongs*/)
62   {
63 
64 	// parameter list is mixed list of * and values
65 	// reference parameters are pointers
66 
67 	unsigned long * mfunc;        // actual function to be invoked
68 	void (*ptr)();
69 	int gpr[4];                   // storage for gpregisters, map to a0-a3
70 	int off;                      // offset used to find function
71 	int nw;                       // number of words mapped
72 	long *p;                      // pointer to parameter overflow area
73 	int c;                        // character of parameter type being decoded
74 	int iret, iret2;              // temporary function return values
75 
76 	// never called
77 	if (! pAdjustedThisPtr ) CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything("xxx"); // address something
78 
79 #ifdef BRDEBUG
80 	fprintf(stderr,"in CallVirtualMethod\n");
81 #endif
82 
83 	// Because of the MIPS O32 calling conventions we could be passing
84 	// parameters in both register types and on the stack. To create the
85 	// stack parameter area we need we now simply allocate local
86 	// variable storage param[] that is at least the size of the parameter stack
87 	// (more than enough space) which we can overwrite the parameters into.
88 
89 	/* p = sp - 512; new sp will be p - 16, but we don't change sp
90 	 * at this time to avoid breaking ABI--not sure whether changing sp will break
91 	 * references to local variables. For the same reason, we use abosulte value.
92 	 */
93 	__asm__ __volatile__ (
94 		"addiu $2,$29,-512\n\t"
95 		"move %0,$2\n\t"
96 		:"=r"(p): : "$2","$29" );
97 
98 #ifdef BRDEBUG
99 	 if (nStackLongs * 4 > 512 )
100 		 fprintf(stderr,"too many arguments");
101 #endif
102 
103 	// now begin to load the C++ function arguments into storage
104 	nw = 0;
105 
106 	// now we need to parse the entire signature string */
107 	// until we get the END indicator */
108 
109 	// treat complex return pointer like any other parameter //
110 
111 #ifdef BRDEBUG
112 	fprintf(stderr,"overflow area pointer p=%p\n",p);
113 
114 	/* Let's figure out what is really going on here*/
115 	fprintf(stderr,"callVirtualMethod paramters string is %s\n",pPT);
116 	int k = nStackLongs;
117 	long * q = (long *)pStackLongs;
118 	while (k > 0) {
119 	  fprintf(stderr,"uno stack is: %x\n",(unsigned int)*q);
120 	  k--;
121 	  q++;
122 	}
123 #endif
124 
125 	/* parse the argument list up to the ending ) */
126 	while (*pPT != 'X') {
127 	  c = *pPT;
128 	  switch (c) {
129 		case 'D':                   /* type is double */
130 		  /* treat the same as long long */
131 		case 'H':                /* type is long long */
132 		  if (nw & 1) nw++; 	/* note even elements gpr[] will map to
133 							   odd registers*/
134 		  if (nw < 4) {
135 			gpr[nw++] = *pStackLongs;
136 			gpr[nw++] = *(pStackLongs+1);
137 		  } else {
138 			if (((long) p) & 4)
139 			  p++;
140 			*p++ = *pStackLongs;
141 			*p++ = *(pStackLongs+1);
142 		  }
143 		  pStackLongs += 2;
144 		  break;
145 
146 		case 'S':
147 		  if (nw < 4) {
148 			gpr[nw++] = *((unsigned short*)pStackLongs);
149 		  } else {
150 			*p++ = *((unsigned short *)pStackLongs);
151 		  }
152 		  pStackLongs += 1;
153 		  break;
154 
155 		case 'B':
156 		  if (nw < 4) {
157 			gpr[nw++] = *((char *)pStackLongs);
158 		  } else {
159 			*p++ = *((char *)pStackLongs);
160 		  }
161 		  pStackLongs += 1;
162 		  break;
163 
164 		default:
165 		  if (nw < 4) {
166 			gpr[nw++] = *pStackLongs;
167 		  } else {
168 			*p++ = *pStackLongs;
169 		  }
170 		  pStackLongs += 1;
171 		  break;
172 	  }
173 	  pPT++;
174 	}
175 
176 	/* figure out the address of the function we need to invoke */
177 	off = nVtableIndex;
178 	off = off * 4;                         // 4 bytes per slot
179 	mfunc = *((unsigned long **)pAdjustedThisPtr);    // get the address of the vtable
180 	mfunc = (unsigned long *)((char *)mfunc + off); // get the address from the vtable entry at offset
181 	mfunc = *((unsigned long **)mfunc);                 // the function is stored at the address
182 	ptr = (void (*)())mfunc;
183 
184 #ifdef BRDEBUG
185 	fprintf(stderr,"calling function %p\n",mfunc);
186 #endif
187 
188 	/* Set up the machine registers and invoke the function */
189 
190 	__asm__ __volatile__ (
191 		"lw	$4,	0(%0)\n\t"
192 		"lw	$5,	4(%0)\n\t"
193 		"lw	$6,	8(%0)\n\t"
194 		"lw	$7,	12(%0)\n\t"
195 		: : "r" (gpr)
196 		: "$4", "$5", "$6", "$7"
197 		);
198 
199 	__asm__ __volatile__ ("addiu $29,$29,-528\r\n":::"$29");
200 
201 	(*ptr)();
202 
203 	__asm__ __volatile__ ("addiu $29,$29,528\r\n":::"$29");
204 
205 	__asm__ __volatile__ (
206 		"sw $2,%0 \n\t"
207 		"sw $3,%1 \n\t"
208 		: "=m" (iret), "=m" (iret2) : );
209 	register float fret asm("$f0");
210 	register double	dret asm("$f0");
211 
212 	switch( eReturnType )
213 	{
214 	  case typelib_TypeClass_HYPER:
215 	  case typelib_TypeClass_UNSIGNED_HYPER:
216 	  	((long*)pRegisterReturn)[1] = iret2;	// fall through
217 	  case typelib_TypeClass_LONG:
218 	  case typelib_TypeClass_UNSIGNED_LONG:
219 	  case typelib_TypeClass_ENUM:
220 		((long*)pRegisterReturn)[0] = iret;
221 		break;
222 	  case typelib_TypeClass_CHAR:
223 	  case typelib_TypeClass_SHORT:
224 	  case typelib_TypeClass_UNSIGNED_SHORT:
225 		*(unsigned short*)pRegisterReturn = (unsigned short)iret;
226 		break;
227 	  case typelib_TypeClass_BOOLEAN:
228 	  case typelib_TypeClass_BYTE:
229 		*(unsigned char*)pRegisterReturn = (unsigned char)iret;
230 		break;
231 	  case typelib_TypeClass_FLOAT:
232 		*(float*)pRegisterReturn = fret;
233 		break;
234 	  case typelib_TypeClass_DOUBLE:
235 		*(double*)pRegisterReturn = dret;
236 		break;
237 	  default:
238 		break;
239 	}
240   }
241 
242 
243   //==================================================================================================
244   static void cpp_call(
245 	  bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
246 	  bridges::cpp_uno::shared::VtableSlot  aVtableSlot,
247 	  typelib_TypeDescriptionReference * pReturnTypeRef,
248 	  sal_Int32 nParams, typelib_MethodParameter * pParams,
249 	  void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
250   {
251 	// max space for: [complex ret ptr], values|ptr ...
252 	char * pCppStack		=
253 	  (char *)alloca( sizeof(sal_Int32) + ((nParams+2) * sizeof(sal_Int64)) );
254 	char * pCppStackStart	= pCppStack;
255 
256 	// need to know parameter types for callVirtualMethod so generate a signature string
257 	char * pParamType = (char *) alloca(nParams+2);
258 	char * pPT = pParamType;
259 
260 #ifdef BRDEBUG
261   fprintf(stderr,"in cpp_call\n");
262 #endif
263 
264 	// return
265 	typelib_TypeDescription * pReturnTypeDescr = 0;
266 	TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
267 	// OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" );
268 
269 	void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
270 
271 	if (pReturnTypeDescr)
272 	{
273 	  if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr ))
274 	  {
275 		pCppReturn = pUnoReturn; // direct way for simple types
276 	  }
277 	  else
278 	  {
279 		// complex return via ptr
280 		pCppReturn = *(void **)pCppStack =
281 		  (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
282 		   ? alloca( pReturnTypeDescr->nSize ): pUnoReturn); // direct way
283 		*pPT++ = 'I'; //signify that a complex return type on stack
284 		pCppStack += sizeof(void *);
285 	  }
286 	}
287 	// push this
288 	void* pAdjustedThisPtr = reinterpret_cast< void **>(pThis->getCppI()) + aVtableSlot.offset;
289 	*(void**)pCppStack = pAdjustedThisPtr;
290 	pCppStack += sizeof( void* );
291 	*pPT++ = 'I';
292 
293 	// stack space
294 	// OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" );
295 	// args
296 	void ** pCppArgs  = (void **)alloca( 3 * sizeof(void *) * nParams );
297 	// indizes of values this have to be converted (interface conversion cpp<=>uno)
298 	sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams);
299 	// type descriptions for reconversions
300 	typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
301 
302 	sal_Int32 nTempIndizes   = 0;
303 
304 	for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
305 	{
306 	  const typelib_MethodParameter & rParam = pParams[nPos];
307 	  typelib_TypeDescription * pParamTypeDescr = 0;
308 	  TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
309 
310 	  if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
311 	  {
312 		uno_copyAndConvertData( pCppArgs[nPos] = pCppStack, pUnoArgs[nPos], pParamTypeDescr,
313 			pThis->getBridge()->getUno2Cpp() );
314 
315 		switch (pParamTypeDescr->eTypeClass)
316 		{
317 
318 		  // we need to know type of each param so that we know whether to use
319 		  // gpr or fpr to pass in parameters:
320 		  // Key: I - int, long, pointer, etc means pass in gpr
321 		  //      B - byte value passed in gpr
322 		  //      S - short value passed in gpr
323 		  //      F - float value pass in fpr
324 		  //      D - double value pass in fpr
325 		  //      H - long long int pass in proper pairs of gpr (3,4) (5,6), etc
326 		  //      X - indicates end of parameter description string
327 
328 		  case typelib_TypeClass_LONG:
329 		  case typelib_TypeClass_UNSIGNED_LONG:
330 		  case typelib_TypeClass_ENUM:
331 			*pPT++ = 'I';
332 			break;
333 		  case typelib_TypeClass_SHORT:
334 		  case typelib_TypeClass_CHAR:
335 		  case typelib_TypeClass_UNSIGNED_SHORT:
336 			*pPT++ = 'S';
337 			break;
338 		  case typelib_TypeClass_BOOLEAN:
339 		  case typelib_TypeClass_BYTE:
340 			*pPT++ = 'B';
341 			break;
342 		  case typelib_TypeClass_FLOAT:
343 			*pPT++ = 'F';
344 			break;
345 		  case typelib_TypeClass_DOUBLE:
346 			*pPT++ = 'D';
347 			pCppStack += sizeof(sal_Int32); // extra long
348 			break;
349 		  case typelib_TypeClass_HYPER:
350 		  case typelib_TypeClass_UNSIGNED_HYPER:
351 			*pPT++ = 'H';
352 			pCppStack += sizeof(sal_Int32); // extra long
353 			break;
354 		  default:
355 			break;
356 		}
357 
358 		// no longer needed
359 		TYPELIB_DANGER_RELEASE( pParamTypeDescr );
360 	  }
361 	  else // ptr to complex value | ref
362 	  {
363 		if (! rParam.bIn) // is pure out
364 		{
365 		  // cpp out is constructed mem, uno out is not!
366 		  uno_constructData(
367 			  *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
368 			  pParamTypeDescr );
369 		  pTempIndizes[nTempIndizes] = nPos; // default constructed for cpp call
370 		  // will be released at reconversion
371 		  ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
372 		}
373 		// is in/inout
374 		else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
375 		{
376 		  uno_copyAndConvertData(
377 			  *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
378 			  pUnoArgs[nPos], pParamTypeDescr,
379 			  pThis->getBridge()->getUno2Cpp() );
380 
381 		  pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
382 		  // will be released at reconversion
383 		  ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
384 		}
385 		else // direct way
386 		{
387 		  *(void **)pCppStack = pCppArgs[nPos] = pUnoArgs[nPos];
388 		  // no longer needed
389 		  TYPELIB_DANGER_RELEASE( pParamTypeDescr );
390 		}
391 		// KBH: FIXME: is this the right way to pass these
392 		*pPT++='I';
393 	  }
394 	  pCppStack += sizeof(sal_Int32); // standard parameter length
395 	}
396 
397 	// terminate the signature string
398 	*pPT++='X';
399 	*pPT=0;
400 
401 	try
402 	{
403 	  OSL_ENSURE( !( (pCppStack - pCppStackStart ) & 3), "UNALIGNED STACK !!! (Please DO panic)" );
404 	  callVirtualMethod(
405 		  pAdjustedThisPtr, aVtableSlot.index,
406 		  pCppReturn, pReturnTypeDescr->eTypeClass, pParamType,
407 		  (sal_Int32 *)pCppStackStart, (pCppStack - pCppStackStart) / sizeof(sal_Int32) );
408 	  // NO exception occured...
409 	  *ppUnoExc = 0;
410 
411 	  // reconvert temporary params
412 	  for ( ; nTempIndizes--; )
413 	  {
414 		sal_Int32 nIndex = pTempIndizes[nTempIndizes];
415 		typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
416 
417 		if (pParams[nIndex].bIn)
418 		{
419 		  if (pParams[nIndex].bOut) // inout
420 		  {
421 			uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
422 			uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
423 				pThis->getBridge()->getCpp2Uno() );
424 		  }
425 		}
426 		else // pure out
427 		{
428 		  uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
429 			  pThis->getBridge()->getCpp2Uno() );
430 		}
431 		// destroy temp cpp param => cpp: every param was constructed
432 		uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
433 
434 		TYPELIB_DANGER_RELEASE( pParamTypeDescr );
435 	  }
436 	  // return value
437 	  if (pCppReturn && pUnoReturn != pCppReturn)
438 	  {
439 		uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
440 			pThis->getBridge()->getCpp2Uno() );
441 		uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
442 	  }
443 	}
444 	catch (...)
445 	{
446 	  // fill uno exception
447 	  fillUnoException( CPPU_CURRENT_NAMESPACE::__cxa_get_globals()->caughtExceptions,
448 		  *ppUnoExc, pThis->getBridge()->getCpp2Uno() );
449 
450 	  // temporary params
451 	  for ( ; nTempIndizes--; )
452 	  {
453 		sal_Int32 nIndex = pTempIndizes[nTempIndizes];
454 		// destroy temp cpp param => cpp: every param was constructed
455 		uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], cpp_release );
456 		TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
457 	  }
458 	  // return type
459 	  if (pReturnTypeDescr)
460 		TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
461 	}
462   }
463 
464 }
465 
466 
467 namespace bridges { namespace cpp_uno { namespace shared {
468 
469 //==================================================================================================
470 void unoInterfaceProxyDispatch(
471 	uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
472     void * pReturn, void * pArgs[], uno_Any ** ppException )
473 {
474   // is my surrogate
475   bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
476 	= static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy *> (pUnoI);
477   //typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
478 
479 #ifdef BRDEBUG
480   fprintf(stderr,"in dispatch\n");
481 #endif
482 
483   switch (pMemberDescr->eTypeClass)
484   {
485 	case typelib_TypeClass_INTERFACE_ATTRIBUTE:
486 	  {
487 
488 		VtableSlot aVtableSlot(
489 			getVtableSlot(
490 			  reinterpret_cast<
491 			  typelib_InterfaceAttributeTypeDescription const * >(
492 				pMemberDescr)));
493 
494 		if (pReturn)
495 		{
496 		  // dependent dispatch
497 		  cpp_call(
498 			  pThis, aVtableSlot,
499 			  ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
500 			  0, 0, // no params
501 			  pReturn, pArgs, ppException );
502 		}
503 		else
504 		{
505 		  // is SET
506 		  typelib_MethodParameter aParam;
507 		  aParam.pTypeRef =
508 			((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
509 		  aParam.bIn		= sal_True;
510 		  aParam.bOut		= sal_False;
511 
512 		  typelib_TypeDescriptionReference * pReturnTypeRef = 0;
513 		  OUString aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") );
514 		  typelib_typedescriptionreference_new(
515 			  &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
516 
517 		  // dependent dispatch
518 		  aVtableSlot.index += 1; //get then set method
519 		  cpp_call(
520 			  pThis, aVtableSlot,
521 			  pReturnTypeRef,
522 			  1, &aParam,
523 			  pReturn, pArgs, ppException );
524 
525 		  typelib_typedescriptionreference_release( pReturnTypeRef );
526 		}
527 
528 		break;
529 	  }
530 	case typelib_TypeClass_INTERFACE_METHOD:
531 	  {
532 
533 		VtableSlot aVtableSlot(
534 			getVtableSlot(
535 			  reinterpret_cast<
536 			  typelib_InterfaceMethodTypeDescription const * >(
537 				pMemberDescr)));
538 		switch (aVtableSlot.index)
539 		{
540 		  // standard calls
541 		  case 1: // acquire uno interface
542 			(*pUnoI->acquire)( pUnoI );
543 			*ppException = 0;
544 			break;
545 		  case 2: // release uno interface
546 			(*pUnoI->release)( pUnoI );
547 			*ppException = 0;
548 			break;
549 		  case 0: // queryInterface() opt
550 			{
551 			  typelib_TypeDescription * pTD = 0;
552 			  TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() );
553 			  if (pTD)
554 			  {
555 				uno_Interface * pInterface = 0;
556 				(*pThis->pBridge->getUnoEnv()->getRegisteredInterface)(
557 																	   pThis->pBridge->getUnoEnv(),
558 																	   (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
559 
560 				if (pInterface)
561 				{
562 				  ::uno_any_construct(
563 					  reinterpret_cast< uno_Any * >( pReturn ),
564 					  &pInterface, pTD, 0 );
565 				  (*pInterface->release)( pInterface );
566 				  TYPELIB_DANGER_RELEASE( pTD );
567 				  *ppException = 0;
568 				  break;
569 				}
570 				TYPELIB_DANGER_RELEASE( pTD );
571 			  }
572 			} // else perform queryInterface()
573 		  default:
574 			// dependent dispatch
575 			cpp_call(
576 				pThis, aVtableSlot,
577 				((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef,
578 				((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams,
579 				((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams,
580 				pReturn, pArgs, ppException );
581 		}
582 		break;
583 	  }
584 	default:
585 	  {
586 		::com::sun::star::uno::RuntimeException aExc(
587 			OUString( RTL_CONSTASCII_USTRINGPARAM("illegal member type description!") ),
588 			::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
589 
590 		Type const & rExcType = ::getCppuType( &aExc );
591 		// binary identical null reference
592 		::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
593 	  }
594   }
595 }
596 }}}
597 
598