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 #include <com/sun/star/uno/genfunc.hxx>
24 #include <typelib/typedescription.hxx>
25 #include <uno/data.h>
26 #include <osl/endian.h>
27 #include "bridges/cpp_uno/shared/bridge.hxx"
28 #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx"
29 #include "bridges/cpp_uno/shared/types.hxx"
30 #include "bridges/cpp_uno/shared/vtablefactory.hxx"
31 #include "share.hxx"
32 
33 #include <stdio.h>
34 #include <string.h>
35 
36 using namespace com::sun::star::uno;
37 
38 //#define BRDEBUG
39 
40 #ifdef BRDEBUG
41 #include <rtl/strbuf.hxx>
42 #include <rtl/ustrbuf.hxx>
43 #include <osl/diagnose.h>
44 #include <osl/mutex.hxx>
45 using namespace ::std;
46 using namespace ::osl;
47 using namespace ::rtl;
48 #endif
49 #include <sys/sysmips.h>
50 
51 #ifdef OSL_BIGENDIAN
52 #define IS_BIG_ENDIAN 1
53 #else
54 #define IS_BIG_ENDIAN 0
55 #endif
56 
57 using namespace ::com::sun::star::uno;
58 
59 namespace
60 {
61 
62   //==================================================================================================
cpp2uno_call(bridges::cpp_uno::shared::CppInterfaceProxy * pThis,const typelib_TypeDescription * pMemberTypeDescr,typelib_TypeDescriptionReference * pReturnTypeRef,sal_Int32 nParams,typelib_MethodParameter * pParams,void ** gpreg,void **,void ** ovrflw,sal_Int64 * pRegisterReturn)63   static typelib_TypeClass cpp2uno_call(
64 	  bridges::cpp_uno::shared::CppInterfaceProxy * pThis,
65 	  const typelib_TypeDescription * pMemberTypeDescr,
66 	  typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return
67 	  sal_Int32 nParams, typelib_MethodParameter * pParams,
68 	  void ** gpreg, void ** /*fpreg*/, void ** ovrflw,
69 	  sal_Int64 * pRegisterReturn /* space for register return */ )
70   {
71 	/*  Most MIPS ABIs view the arguments as a struct, of which the
72 		first N words go in registers and the rest go on the stack.  If I < N, the
73 		Ith word might go in Ith integer argument register or the Ith
74 		floating-point one.  For these ABIs, we only need to remember the number
75 		of words passed so far.  We are interested only in o32 ABI,so it is the
76 		case.
77 		*/
78 	int nw = 0; // number of words used by arguments
79 
80 #ifdef BRDEBUG
81 	fprintf(stderr,"cpp2uno_call1\n");
82 #endif
83 
84 	/* C++ has [ret *] or this as the first arguments, so no arguments will
85 	 * be passed in floating-point registers?
86 	 */
87 	//int int_seen = 0; // have we seen integer arguments?
88 
89 	void ** pCppStack; //temporary stack pointer
90 
91 	// gpreg:  [ret *], this, [gpr params]
92 	// fpreg:  [fpr params]
93 	// ovrflw: [gpr or fpr params (properly aligned)]
94 
95 	// return
96 	typelib_TypeDescription * pReturnTypeDescr = 0;
97 	if (pReturnTypeRef)
98 	  TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
99 
100 	void * pUnoReturn = 0;
101 	void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
102 
103 	if (pReturnTypeDescr)
104 	{
105 	  if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr ))
106 	  {
107 		pUnoReturn = pRegisterReturn; // direct way for simple types
108 #ifdef BRDEBUG
109 	fprintf(stderr,"cpp2uno_call:simplereturn\n");
110 #endif
111 	  }
112 	  else // complex return via ptr (pCppReturn)
113 	  {
114 		pCppReturn = *(void **)gpreg;
115 		gpreg++;
116 		nw++;
117 
118 		pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
119 			? alloca( pReturnTypeDescr->nSize )
120 			: pCppReturn); // direct way
121 #ifdef BRDEBUG
122 	fprintf(stderr,"cpp2uno_call:complexreturn\n");
123 #endif
124 	  }
125 	}
126 
127 	// pop this
128 	gpreg++;
129 	nw++;
130 
131 	// stack space
132 	OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" );
133 	// parameters
134 	void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams );
135 	void ** pCppArgs = pUnoArgs + nParams;
136 	// indizes of values this have to be converted (interface conversion cpp<=>uno)
137 	sal_Int32 * pTempIndizes = (sal_Int32 *)(pUnoArgs + (2 * nParams));
138 	// type descriptions for reconversions
139 	typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams));
140 
141 	sal_Int32 nTempIndizes   = 0;
142 
143 #ifdef BRDEBUG
144 	fprintf(stderr,"cpp2uno_call:nParams=%d\n",nParams);
145 #endif
146 
147 	for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
148 	{
149 	  const typelib_MethodParameter & rParam = pParams[nPos];
150 	  typelib_TypeDescription * pParamTypeDescr = 0;
151 	  TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
152 
153 	  if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
154 		// value
155 	  {
156 
157 		switch (pParamTypeDescr->eTypeClass)
158 		{
159 		  case typelib_TypeClass_DOUBLE:
160 		  case typelib_TypeClass_HYPER:
161 		  case typelib_TypeClass_UNSIGNED_HYPER:
162 #ifdef BRDEBUG
163 	fprintf(stderr,"cpp2uno_call:hyper=%d,%p\n",pParamTypeDescr->eTypeClass,gpreg[0]);
164 #endif
165 			if (nw < 3) {
166 			  if (nw & 1) {
167 				nw++;
168 				gpreg++;
169 			  }
170 #ifdef BRDEBUG
171 	fprintf(stderr,"cpp2uno_call:gpreg=%p,%p\n",gpreg[0],gpreg[1]);
172 #endif
173 			  pCppArgs[nPos] = gpreg;
174 			  pUnoArgs[nPos] = gpreg;
175 			  nw += 2;
176 			  gpreg += 2;
177 			} else {
178 			  if (((long)ovrflw) & 4) ovrflw++;
179 #ifdef BRDEBUG
180 	fprintf(stderr,"cpp2uno_call:overflw=%p,%p\n",ovrflw[0],ovrflw[1]);
181 #endif
182 			  pCppArgs[nPos] = ovrflw;
183 			  pUnoArgs[nPos] = ovrflw;
184 			  ovrflw += 2;
185 			}
186 			break;
187 
188 		  case typelib_TypeClass_BYTE:
189 		  case typelib_TypeClass_BOOLEAN:
190 #ifdef BRDEBUG
191 	fprintf(stderr,"cpp2uno_call:byte=%p,%p\n",gpreg[0],ovrflw[0]);
192 #endif
193 			if (nw < 4) {
194 			  pCppArgs[nPos] = ((char *)gpreg + 3*IS_BIG_ENDIAN);
195 			  pUnoArgs[nPos] = ((char *)gpreg + 3*IS_BIG_ENDIAN);
196 			  nw++;
197 			  gpreg++;
198 			} else {
199 			  pCppArgs[nPos] = ((char *)ovrflw + 3*IS_BIG_ENDIAN);
200 			  pUnoArgs[nPos] = ((char *)ovrflw + 3*IS_BIG_ENDIAN);
201 			  ovrflw++;
202 			}
203 			break;
204 
205 
206 		  case typelib_TypeClass_CHAR:
207 		  case typelib_TypeClass_SHORT:
208 		  case typelib_TypeClass_UNSIGNED_SHORT:
209 #ifdef BRDEBUG
210 	fprintf(stderr,"cpp2uno_call:char=%p,%p\n",gpreg[0],ovrflw[0]);
211 #endif
212 			if (nw < 4) {
213 			  pCppArgs[nPos] = ((char *)gpreg + 2*IS_BIG_ENDIAN);
214 			  pUnoArgs[nPos] = ((char *)gpreg + 2*IS_BIG_ENDIAN);
215 			  nw++;
216 			  gpreg++;
217 			} else {
218 			  pCppArgs[nPos] = ((char *)ovrflw + 2*IS_BIG_ENDIAN);
219 			  pUnoArgs[nPos] = ((char *)ovrflw + 2*IS_BIG_ENDIAN);
220 			  ovrflw++;
221 			}
222 			break;
223 
224 
225 		  default:
226 #ifdef BRDEBUG
227 	fprintf(stderr,"cpp2uno_call:def=%p,%p\n",gpreg[0],ovrflw[0]);
228 #endif
229 			if (nw < 4) {
230 			  pCppArgs[nPos] = gpreg;
231 			  pUnoArgs[nPos] = gpreg;
232 			  nw++;
233 			  gpreg++;
234 			} else {
235 			  pCppArgs[nPos] = ovrflw;
236 			  pUnoArgs[nPos] = ovrflw;
237 			  ovrflw++;
238 			}
239 			break;
240 
241 		}
242 		// no longer needed
243 		TYPELIB_DANGER_RELEASE( pParamTypeDescr );
244 	  }
245 	  else // ptr to complex value | ref
246 	  {
247 
248 #ifdef BRDEBUG
249 	fprintf(stderr,"cpp2uno_call:ptr|ref\n");
250 #endif
251 		if (nw < 4) {
252 		  pCppArgs[nPos] = *(void **)gpreg;
253 		  pCppStack = gpreg;
254 		  nw++;
255 		  gpreg++;
256 		} else {
257 		  pCppArgs[nPos] = *(void **)ovrflw;
258 		  pCppStack = ovrflw;
259 		  ovrflw++;
260 		}
261 #ifdef BRDEBUG
262 	fprintf(stderr,"cpp2uno_call:pCppStack=%p\n",pCppStack);
263 #endif
264 
265 		if (! rParam.bIn) // is pure out
266 		{
267 		  // uno out is unconstructed mem!
268 		  pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
269 		  pTempIndizes[nTempIndizes] = nPos;
270 		  // will be released at reconversion
271 		  ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
272 		}
273 		// is in/inout
274 		else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
275 		{
276 		  uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
277 			  *(void **)pCppStack, pParamTypeDescr,
278 			  pThis->getBridge()->getCpp2Uno() );
279 		  pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
280 		  // will be released at reconversion
281 		  ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
282 #ifdef BRDEBUG
283 	fprintf(stderr,"cpp2uno_call:related to interface,%p,%d,pUnoargs[%d]=%p\n",*(void**)pCppStack,pParamTypeDescr->nSize,nPos,pUnoArgs[nPos]);
284 #endif
285 		}
286 		else // direct way
287 		{
288 		  pUnoArgs[nPos] = *(void **)pCppStack;
289 #ifdef BRDEBUG
290 	fprintf(stderr,"cpp2uno_call:direct,pUnoArgs[%d]=%p\n",nPos,pUnoArgs[nPos]);
291 #endif
292 		  // no longer needed
293 		  TYPELIB_DANGER_RELEASE( pParamTypeDescr );
294 		}
295 	  }
296 	}
297 #ifdef BRDEBUG
298 	fprintf(stderr,"cpp2uno_call2,%p,unoargs=%p\n",pThis->getUnoI()->pDispatcher,pUnoArgs);
299 #endif
300 
301 	// ExceptionHolder
302 	uno_Any aUnoExc; // Any will be constructed by callee
303 	uno_Any * pUnoExc = &aUnoExc;
304 
305 	// invoke uno dispatch call
306 	(*pThis->getUnoI()->pDispatcher)( pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
307 #ifdef BRDEBUG
308 	fprintf(stderr,"cpp2uno_call2,after dispatch\n");
309 #endif
310 
311 	// in case an exception occured...
312 	if (pUnoExc)
313 	{
314 	  // destruct temporary in/inout params
315 	  for ( ; nTempIndizes--; )
316 	  {
317 		sal_Int32 nIndex = pTempIndizes[nTempIndizes];
318 
319 		if (pParams[nIndex].bIn) // is in/inout => was constructed
320 		  uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], 0 );
321 		TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
322 	  }
323 	  if (pReturnTypeDescr)
324 		TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
325 
326 	  CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc, pThis->getBridge()->getUno2Cpp() );
327 	  // has to destruct the any
328 	  // is here for dummy
329 	  return typelib_TypeClass_VOID;
330 	}
331 	else // else no exception occured...
332 	{
333 	  // temporary params
334 	  for ( ; nTempIndizes--; )
335 	  {
336 		sal_Int32 nIndex = pTempIndizes[nTempIndizes];
337 		typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
338 
339 		if (pParams[nIndex].bOut) // inout/out
340 		{
341 		  // convert and assign
342 		  uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
343 		  uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
344 			  pThis->getBridge()->getUno2Cpp() );
345 		}
346 		// destroy temp uno param
347 		uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
348 
349 		TYPELIB_DANGER_RELEASE( pParamTypeDescr );
350 	  }
351 	  // return
352 	  if (pCppReturn) // has complex return
353 	  {
354 		if (pUnoReturn != pCppReturn) // needs reconversion
355 		{
356 		  uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
357 			  pThis->getBridge()->getUno2Cpp() );
358 		  // destroy temp uno return
359 		  uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
360 		}
361 		// complex return ptr is set to return reg
362 		*(void **)pRegisterReturn = pCppReturn;
363 	  }
364 	  if (pReturnTypeDescr)
365 	  {
366 		typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
367 		TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
368 		return eRet;
369 	  }
370 	  else
371 		return typelib_TypeClass_VOID;
372 	}
373   }
374 
375 
376   //==================================================================================================
cpp_mediate(sal_Int32 nFunctionIndex,sal_Int32 nVtableOffset,void ** gpreg,void ** fpreg,void ** ovrflw,sal_Int64 * pRegisterReturn)377   static typelib_TypeClass cpp_mediate(
378 	  sal_Int32 nFunctionIndex,
379 	  sal_Int32 nVtableOffset,
380 	  void ** gpreg, void ** fpreg, void ** ovrflw,
381 	  sal_Int64 * pRegisterReturn /* space for register return */ )
382   {
383 	OSL_ENSURE( sizeof(sal_Int32)==sizeof(void *), "### unexpected!" );
384 
385 #ifdef BRDEBUG
386 	fprintf(stderr,"cpp_mediate1 gp=%p,fp=%p,ov=%p\n",gpreg,fpreg,ovrflw);
387 	fprintf(stderr,"gp=%x,%x,%x,%x\n",gpreg[0],gpreg[1],gpreg[2],gpreg[3]);
388 #endif
389 
390 	// gpreg:  [ret *], this, [other gpr params]
391 	// fpreg:  [fpr params]
392 	// ovrflw: [gpr or fpr params (properly aligned)]
393 
394 	void * pThis;
395 	if (nFunctionIndex & 0x80000000 )
396 	{
397 	  nFunctionIndex &= 0x7fffffff;
398 	  pThis = gpreg[1];
399 	}
400 	else
401 	{
402 	  pThis = gpreg[0];
403 	}
404 #ifdef BRDEBUG
405 	fprintf(stderr,"cpp_mediate12,pThis=%p, nFunctionIndex=%d,nVtableOffset=%d\n",pThis,nFunctionIndex,nVtableOffset);
406 #endif
407 
408 	pThis = static_cast< char * >(pThis) - nVtableOffset;
409 	bridges::cpp_uno::shared::CppInterfaceProxy * pCppI
410 	  = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
411 		  pThis);
412 #ifdef BRDEBUG
413 	fprintf(stderr,"cpp_mediate13,pCppI=%p\n",pCppI);
414 #endif
415 
416 	typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
417 
418 #ifdef BRDEBUG
419 	fprintf(stderr,"cpp_mediate2\n");
420 #endif
421 	OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!" );
422 	if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
423 	{
424 	  throw RuntimeException(
425 		  rtl::OUString::createFromAscii("illegal vtable index!"),
426 		  (XInterface *)pThis );
427 	}
428 
429 	// determine called method
430 	sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
431 	OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!" );
432 
433 	TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
434 
435 #ifdef BRDEBUG
436 	fprintf(stderr,"cpp_mediate3\n");
437 	OString cstr( OUStringToOString( aMemberDescr.get()->pTypeName, RTL_TEXTENCODING_ASCII_US ) );
438 	fprintf( stderr, "calling %s, nFunctionIndex=%d\n", cstr.getStr(), nFunctionIndex );
439 #endif
440 	typelib_TypeClass eRet;
441 	switch (aMemberDescr.get()->eTypeClass)
442 	{
443 	  case typelib_TypeClass_INTERFACE_ATTRIBUTE:
444 		{
445 #ifdef BRDEBUG
446 	fprintf(stderr,"cpp_mediate4\n");
447 #endif
448 		  if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex)
449 		  {
450 			// is GET method
451 			eRet = cpp2uno_call(
452 				pCppI, aMemberDescr.get(),
453 				((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef,
454 				0, 0, // no params
455 				gpreg, fpreg, ovrflw, pRegisterReturn );
456 		  }
457 		  else
458 		  {
459 			// is SET method
460 			typelib_MethodParameter aParam;
461 			aParam.pTypeRef =
462 			  ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef;
463 			aParam.bIn		= sal_True;
464 			aParam.bOut		= sal_False;
465 
466 			eRet = cpp2uno_call(
467 				pCppI, aMemberDescr.get(),
468 				0, // indicates void return
469 				1, &aParam,
470 				gpreg, fpreg, ovrflw, pRegisterReturn );
471 		  }
472 		  break;
473 		}
474 	  case typelib_TypeClass_INTERFACE_METHOD:
475 		{
476 #ifdef BRDEBUG
477 	fprintf(stderr,"cpp_mediate5\n");
478 #endif
479 		  // is METHOD
480 		  switch (nFunctionIndex)
481 		  {
482 			case 1: // acquire()
483 			  pCppI->acquireProxy(); // non virtual call!
484 			  eRet = typelib_TypeClass_VOID;
485 			  break;
486 			case 2: // release()
487 #ifdef BRDEBUG
488 	fprintf(stderr,"cpp_mediate51\n");
489 #endif
490 			  pCppI->releaseProxy(); // non virtual call!
491 			  eRet = typelib_TypeClass_VOID;
492 #ifdef BRDEBUG
493 	fprintf(stderr,"cpp_mediate52\n");
494 #endif
495 			  break;
496 			case 0: // queryInterface() opt
497 			  {
498 				typelib_TypeDescription * pTD = 0;
499 				TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( gpreg[2] )->getTypeLibType() );
500 				if (pTD)
501 				{
502 				  XInterface * pInterface = 0;
503 				  (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
504 																			 pCppI->getBridge()->getCppEnv(),
505 																			 (void **)&pInterface, pCppI->getOid().pData,
506 																			 (typelib_InterfaceTypeDescription *)pTD );
507 
508 				  if (pInterface)
509 				  {
510 					::uno_any_construct(
511 						reinterpret_cast< uno_Any * >( gpreg[0] ),
512 						&pInterface, pTD, cpp_acquire );
513 					pInterface->release();
514 					TYPELIB_DANGER_RELEASE( pTD );
515 					*(void **)pRegisterReturn = gpreg[0];
516 					eRet = typelib_TypeClass_ANY;
517 					break;
518 				  }
519 				  TYPELIB_DANGER_RELEASE( pTD );
520 				}
521 			  } // else perform queryInterface()
522 			default:
523 			  eRet = cpp2uno_call(
524 				  pCppI, aMemberDescr.get(),
525 				  ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef,
526 				  ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams,
527 				  ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams,
528 				  gpreg, fpreg, ovrflw, pRegisterReturn );
529 		  }
530 		  break;
531 		}
532 	  default:
533 		{
534 #ifdef BRDEBUG
535 	fprintf(stderr,"cpp_mediate6\n");
536 #endif
537 		  throw RuntimeException(
538 			  rtl::OUString::createFromAscii("no member description found!"),
539 			  (XInterface *)pThis );
540 		  // is here for dummy
541 		  eRet = typelib_TypeClass_VOID;
542 		}
543 	}
544 
545 	return eRet;
546   }
547 
548   //==================================================================================================
549   /**
550    * is called on incoming vtable calls
551    * (called by asm snippets)
552    */
553 //  static void cpp_vtable_call( int nFunctionIndex, int nVtableOffset, void** gpregptr, void** fpregptr, void** ovrflw)
554 //  static void cpp_vtable_call( int nFunctionIndex, int nVtableOffset, void** gpregptr, void** ovrflw)
cpp_vtable_call(void)555   static void cpp_vtable_call(void)
556   {
557 	int nFunctionIndex;
558 	int vTableOffset;
559 	void** pCallStack;
560 	void** ovrflw;
561 
562 	sal_Int32     gpreg[4];
563 	double        fpreg[2];
564 
565 	//memcpy( fpreg, fpregptr, 16);
566 
567 	volatile long nRegReturn[2];
568 
569 	__asm__( "sw $4, %0\n\t"
570 		 "sw $5, %1\n\t"
571 		 "sw $6, %2\n\t"
572 		 "sw $7, %3\n\t"
573 			::"m"(nFunctionIndex), "m"(vTableOffset), "m"(pCallStack), "m"(ovrflw) );
574 
575 	memcpy( gpreg, pCallStack, 16);
576 
577 #ifdef BRDEBUG
578 	fprintf(stderr,"in cpp_vtable_call nFunctionIndex is %d\n",nFunctionIndex);
579 	fprintf(stderr,"in cpp_vtable_call nVtableOffset is %d\n",vTableOffset);
580 	fprintf(stderr,"gp=%x,%x,%x,%x\n",gpreg[0],gpreg[1],gpreg[2],gpreg[3]);
581 #endif
582 
583 	//sal_Bool bComplex = nFunctionIndex & 0x80000000 ? sal_True : sal_False;
584 
585 	typelib_TypeClass aType =
586 	  cpp_mediate( nFunctionIndex, vTableOffset, (void**)gpreg, (void**)fpreg, ovrflw, (sal_Int64*)nRegReturn );
587 
588 	switch( aType )
589 	{
590 
591 	  // move return value into register space
592 	  // (will be loaded by machine code snippet)
593 
594 	  case typelib_TypeClass_BOOLEAN:
595 	  case typelib_TypeClass_BYTE:
596 		__asm__( "lbu $2,%0\n\t" : :
597 			"m"(nRegReturn[0]) );
598 		break;
599 
600 	  case typelib_TypeClass_CHAR:
601 	  case typelib_TypeClass_UNSIGNED_SHORT:
602 		__asm__( "lhu $2,%0\n\t" : :
603 			"m"(nRegReturn[0]) );
604 		break;
605 
606 	  case typelib_TypeClass_SHORT:
607 		__asm__( "lh $2,%0\n\t" : :
608 			"m"(nRegReturn[0]) );
609 		break;
610 
611 
612 	  case typelib_TypeClass_FLOAT:
613 		__asm__( "lwc1 $f0,%0\n\t" : :
614 			"m" (*((float*)nRegReturn)) );
615 		break;
616 
617 	  case typelib_TypeClass_DOUBLE:
618 	  	{ register double dret asm("$f0");
619 		dret = (*((double*)nRegReturn)); }
620 		break;
621 
622 	  case typelib_TypeClass_HYPER:
623 	  case typelib_TypeClass_UNSIGNED_HYPER:
624 		__asm__( "lw $3,%0\n\t" : :
625 			"m"(nRegReturn[1]) );  // fall through
626 
627 	  default:
628 		__asm__( "lw $2,%0\n\t" : :
629 			"m"(nRegReturn[0]) );
630 		break;
631 	}
632   }
633 
634 
635   int const codeSnippetSize = 56;
636 
codeSnippet(unsigned char * code,sal_Int32 functionIndex,sal_Int32 vtableOffset,bool simpleRetType)637   unsigned char *  codeSnippet( unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset,
638 	  bool simpleRetType)
639   {
640 
641 #ifdef BRDEBUG
642 	 fprintf(stderr,"in codeSnippet functionIndex is %d\n", functionIndex);
643 	 fprintf(stderr,"in codeSnippet vtableOffset is %d\n", vtableOffset);
644 	 fflush(stderr);
645 #endif
646 
647 	if (! simpleRetType )
648 	  functionIndex |= 0x80000000;
649 
650 	unsigned long * p = (unsigned long *) code;
651 
652 	// OSL_ASSERT( sizeof (long) == 4 );
653 	OSL_ASSERT((((unsigned long)code) & 0x3) == 0 );  //aligned to 4 otherwise a mistake
654 
655 	/* generate this code */
656 	/*
657 	   #save regs into argument space required by mips abi
658             c:   afa40000        sw      a0,0(sp)
659 	   10:   afa50004        sw      a1,4(sp)
660 	   14:   afa60008        sw      a2,8(sp)
661 	   18:   afa7000c        sw      a3,12(sp)
662        #a0=index
663 	   1c:   3c040000        lui     a0,0x0
664 	   20:   34840000        ori     a0,a0,0x0
665        #a1=offset
666 	   24:   3c050000        lui     a1,0x0
667 	   28:   34a50000        ori     a1,a1,0x0
668        #a2=gpregptr
669 	   2c:   27a60000        addiu   a2,sp,0
670        #a3=ovrflw
671 	   30:   27a70010        addiu   a3,sp,16
672        #load cpp_vtable_call addr
673 	   34:   3c190000        lui     t9,0x0
674 	   38:   37390000        ori     t9,t9,0
675        #jmp to the function,note: we don't use jalr, that will destroy $ra
676        #but be sure to use t9! gp calculation depends on it
677 	   3c:   03200008        jr      t9
678 	   40:   00000000        nop
679 
680        be careful, we use the argument space reserved by the caller to
681 	   write down regs. This can avoid the need to make use of arbitary far away
682 	   stack space or to allocate a function frame for this code snippet itself.
683 	   Since only functions with variable arguments will overwrite the space,
684 	   cpp_vtable_call should be safe.
685 	   ??? gcc seems change this behavior! cpp_vtable_call overwrite the space!
686 	 */
687 
688 	* p++ = 0xafa40000;
689 	* p++ = 0xafa50004;
690 	* p++ = 0xafa60008;
691 	* p++ = 0xafa7000c;
692 	* p++ = 0x3c040000 | ((functionIndex>>16) & 0x0000ffff);
693 	* p++ = 0x34840000 | (functionIndex & 0x0000ffff);
694 	* p++ = 0x3c050000 | ((vtableOffset>>16) & 0x0000ffff);
695 	* p++ = 0x34a50000 | (vtableOffset & 0x0000ffff);
696 	* p++ = 0x27a60000;
697 	* p++ = 0x27a70010;
698 	* p++ = 0x3c190000 | ((((unsigned long)cpp_vtable_call) >> 16) & 0x0000ffff);
699 	* p++ = 0x37390000 | (((unsigned long)cpp_vtable_call) & 0x0000FFFF);
700 	* p++ = 0x03200008;
701 	* p++ = 0x00000000;
702 	return (code + codeSnippetSize);
703 
704   }
705 
706 
707 }
708 
709 
710 #define MIN_LINE_SIZE 32
711 
flushCode(unsigned char const *,unsigned char const *)712 void bridges::cpp_uno::shared::VtableFactory::flushCode(unsigned char const * /*bptr*/, unsigned char const * /*eptr*/)
713 {
714   sysmips(FLUSH_CACHE,0,0,0);
715 }
716 
717 struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; };
718 
719 bridges::cpp_uno::shared::VtableFactory::Slot *
mapBlockToVtable(void * block)720 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
721 {
722     return static_cast< Slot * >(block) + 2;
723 }
724 
725 
getBlockSize(sal_Int32 slotCount)726 sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize(
727     sal_Int32 slotCount)
728 {
729     return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
730 }
731 
732 bridges::cpp_uno::shared::VtableFactory::Slot *
initializeBlock(void * block,sal_Int32 slotCount)733 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
734     void * block, sal_Int32 slotCount)
735 {
736     Slot * slots = mapBlockToVtable(block);
737     slots[-2].fn = 0; //null
738     slots[-1].fn = 0; //destructor
739     return slots + slotCount;
740 }
741 
addLocalFunctions(Slot ** slots,unsigned char * code,sal_PtrDiff writetoexecdiff,typelib_InterfaceTypeDescription const * type,sal_Int32 functionOffset,sal_Int32 functionCount,sal_Int32 vtableOffset)742 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
743 	Slot ** slots, unsigned char * code, sal_PtrDiff writetoexecdiff,
744 	typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
745 	sal_Int32 functionCount, sal_Int32 vtableOffset)
746 {
747    (*slots) -= functionCount;
748     Slot * s = *slots;
749 #ifdef BRDEBUG
750    fprintf(stderr, "in addLocalFunctions functionOffset is %d\n",functionOffset);
751    fprintf(stderr, "in addLocalFunctions vtableOffset is %d\n",vtableOffset);
752    fprintf(stderr, "nMembers=%d\n",type->nMembers);
753    fflush(stderr);
754 #endif
755 
756   for (sal_Int32 i = 0; i < type->nMembers; ++i) {
757 	typelib_TypeDescription * member = 0;
758 	TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
759 	OSL_ASSERT(member != 0);
760 	switch (member->eTypeClass) {
761 	  case typelib_TypeClass_INTERFACE_ATTRIBUTE:
762 		// Getter:
763 		(s++)->fn = code + writetoexecdiff;
764 		code = codeSnippet(
765 			code, functionOffset++, vtableOffset,
766 			bridges::cpp_uno::shared::isSimpleType(
767 			  reinterpret_cast<
768 			  typelib_InterfaceAttributeTypeDescription * >(
769 				member)->pAttributeTypeRef));
770 
771 		// Setter:
772 		if (!reinterpret_cast<
773 			typelib_InterfaceAttributeTypeDescription * >(
774 			  member)->bReadOnly)
775 		{
776 		  (s++)->fn = code + writetoexecdiff;
777 		  code = codeSnippet(code, functionOffset++, vtableOffset, true);
778 		}
779 		break;
780 
781 	  case typelib_TypeClass_INTERFACE_METHOD:
782 		(s++)->fn = code + writetoexecdiff;
783 		code = codeSnippet(
784 			code, functionOffset++, vtableOffset,
785 			bridges::cpp_uno::shared::isSimpleType(
786 			  reinterpret_cast<
787 			  typelib_InterfaceMethodTypeDescription * >(
788 				member)->pReturnTypeRef));
789 		break;
790 
791 	  default:
792 		OSL_ASSERT(false);
793 		break;
794 	}
795 	TYPELIB_DANGER_RELEASE(member);
796   }
797   return code;
798 }
799 
800