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