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 #include <hash_map>
30 
31 #include <rtl/alloc.h>
32 #include <osl/mutex.hxx>
33 
34 #include <com/sun/star/uno/genfunc.hxx>
35 #include "com/sun/star/uno/RuntimeException.hpp"
36 #include <uno/data.h>
37 #include <typelib/typedescription.hxx>
38 
39 #include "bridges/cpp_uno/shared/bridge.hxx"
40 #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx"
41 #include "bridges/cpp_uno/shared/types.hxx"
42 #include "bridges/cpp_uno/shared/vtablefactory.hxx"
43 
44 #include "share.hxx"
45 
46 #include <dlfcn.h>
47 
48 
49 using namespace ::osl;
50 using namespace ::rtl;
51 using namespace ::com::sun::star::uno;
52 
53 namespace
54 {
55 
56     static typelib_TypeClass cpp2uno_call(
57         bridges::cpp_uno::shared::CppInterfaceProxy* pThis,
58         const typelib_TypeDescription * pMemberTypeDescr,
59         typelib_TypeDescriptionReference * pReturnTypeRef,
60         sal_Int32 nParams, typelib_MethodParameter * pParams,
61         long r8, void ** gpreg, double *fpreg, void ** ovrflw,
62         sal_Int64 * pRegisterReturn /* space for register return */ )
63     {
64         void ** startovrflw = ovrflw;
65         int nregs = 0; //number of words passed in registers
66 
67 #ifdef CMC_DEBUG
68 	fprintf(stderr, "cpp2uno_call\n");
69 #endif
70         // return
71         typelib_TypeDescription * pReturnTypeDescr = 0;
72         if (pReturnTypeRef)
73             TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
74 
75         void * pUnoReturn = 0;
76         // complex return ptr: if != 0 && != pUnoReturn, reconversion need
77         void * pCppReturn = 0;
78 
79         if (pReturnTypeDescr)
80         {
81             if (hppa::isRegisterReturn(pReturnTypeRef))
82             {
83 #ifdef CMC_DEBUG
84 		fprintf(stderr, "simple return\n");
85 #endif
86                 pUnoReturn = pRegisterReturn; // direct way for simple types
87             }
88             else
89             {
90 #ifdef CMC_DEBUG
91 		fprintf(stderr, "complex return via r8\n");
92 #endif
93                 pCppReturn = (void *)r8;
94 
95                 pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
96                     ? alloca( pReturnTypeDescr->nSize )
97                     : pCppReturn); // direct way
98             }
99         }
100         // pop this
101         gpreg++;
102         fpreg++;
103         nregs++;
104 
105         // stack space
106         OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" );
107         // parameters
108         void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams );
109         void ** pCppArgs = pUnoArgs + nParams;
110         // indizes of values this have to be converted (interface conversion
111         // cpp<=>uno)
112         sal_Int32 * pTempIndizes = (sal_Int32 *)(pUnoArgs + (2 * nParams));
113         // type descriptions for reconversions
114         typelib_TypeDescription ** ppTempParamTypeDescr =
115             (typelib_TypeDescription **)(pUnoArgs + (3 * nParams));
116 
117         sal_Int32 nTempIndizes   = 0;
118         bool bOverFlowUsed = false;
119         for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
120         {
121             const typelib_MethodParameter & rParam = pParams[nPos];
122             typelib_TypeDescription * pParamTypeDescr = 0;
123             TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
124 
125             if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
126             {
127                 switch (pParamTypeDescr->eTypeClass)
128                 {
129                     case typelib_TypeClass_DOUBLE:
130                         if (nregs < hppa::MAX_WORDS_IN_REGS && (nregs & 1))
131                         {
132                             gpreg++;
133                             fpreg++;
134                             nregs++;
135                         }
136                         if (nregs < hppa::MAX_WORDS_IN_REGS-1)
137                         {
138                             fpreg++;
139                             pCppArgs[nPos] = pUnoArgs[nPos] = fpreg;
140                             gpreg+=2;
141                             fpreg+=2;
142                             nregs+=2;
143                         }
144                         else
145                         {
146                             if ((startovrflw-ovrflw) & 1)
147                                 ovrflw--;
148                             pCppArgs[nPos] = pUnoArgs[nPos] = ((char*)ovrflw - 4);
149                             bOverFlowUsed = true;
150                         }
151                         if (bOverFlowUsed) ovrflw-=2;
152                         break;
153                     case typelib_TypeClass_FLOAT:
154                         if (nregs < hppa::MAX_WORDS_IN_REGS)
155                         {
156                             pCppArgs[nPos] = pUnoArgs[nPos] = fpreg;
157                             gpreg++;
158                             fpreg++;
159                             nregs++;
160                         }
161                         else
162                         {
163                             pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw;
164                             bOverFlowUsed = true;
165                         }
166                         if (bOverFlowUsed) ovrflw--;
167                         break;
168                     case typelib_TypeClass_HYPER:
169                     case typelib_TypeClass_UNSIGNED_HYPER:
170                         if (nregs < hppa::MAX_WORDS_IN_REGS && (nregs & 1))
171                         {
172                             gpreg++;
173                             fpreg++;
174                             nregs++;
175                         }
176                         if (nregs < hppa::MAX_WORDS_IN_REGS-1)
177                         {
178                             pCppArgs[nPos] = pUnoArgs[nPos] = gpreg;
179                             gpreg+=2;
180                             fpreg+=2;
181                             nregs+=2;
182                         }
183                         else
184                         {
185                             if ((startovrflw-ovrflw) & 1)
186                                 ovrflw--;
187                             pCppArgs[nPos] = pUnoArgs[nPos] = ((char*)ovrflw - 4);
188                             bOverFlowUsed = true;
189                         }
190                         if (bOverFlowUsed) ovrflw-=2;
191                         break;
192                     case typelib_TypeClass_BYTE:
193                     case typelib_TypeClass_BOOLEAN:
194                         if (nregs < hppa::MAX_WORDS_IN_REGS)
195                         {
196                             pCppArgs[nPos] = pUnoArgs[nPos] = ((char*)gpreg + 3);
197                             gpreg++;
198                             fpreg++;
199                             nregs++;
200                         }
201                         else
202                         {
203                             pCppArgs[nPos] = pUnoArgs[nPos] = ((char*)ovrflw+3);
204                             bOverFlowUsed = true;
205                         }
206                         if (bOverFlowUsed) ovrflw--;
207                         break;
208                     case typelib_TypeClass_CHAR:
209                     case typelib_TypeClass_SHORT:
210                     case typelib_TypeClass_UNSIGNED_SHORT:
211                         if (nregs < hppa::MAX_WORDS_IN_REGS)
212                         {
213                             pCppArgs[nPos] = pUnoArgs[nPos] = ((char*)gpreg+2);
214                             gpreg++;
215                             fpreg++;
216                             nregs++;
217                         }
218                         else
219                         {
220                             pCppArgs[nPos] = pUnoArgs[nPos] = ((char*)ovrflw+2);
221                             bOverFlowUsed = true;
222                         }
223                         if (bOverFlowUsed) ovrflw--;
224                         break;
225                     case typelib_TypeClass_ENUM:
226                     case typelib_TypeClass_LONG:
227                     case typelib_TypeClass_UNSIGNED_LONG:
228                     default:
229                         if (nregs < hppa::MAX_WORDS_IN_REGS)
230                         {
231                             pCppArgs[nPos] = pUnoArgs[nPos] = gpreg;
232                             gpreg++;
233                             fpreg++;
234                             nregs++;
235                         }
236                         else
237                         {
238                             pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw;
239                             bOverFlowUsed = true;
240                         }
241                         if (bOverFlowUsed) ovrflw--;
242                         break;
243                 }
244                 // no longer needed
245                 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
246             }
247             else // ptr to complex value | ref
248             {
249                 void *pCppStack;
250 
251                 if (nregs < hppa::MAX_WORDS_IN_REGS)
252                 {
253                     pCppArgs[nPos] = pCppStack = *gpreg;
254                     gpreg++;
255                     fpreg++;
256                     nregs++;
257                 }
258                 else
259                 {
260                     pCppArgs[nPos] = pCppStack = *ovrflw;
261                     bOverFlowUsed = true;
262                 }
263                 if (bOverFlowUsed) ovrflw--;
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(
275                     pParamTypeDescr ))
276                 {
277                    uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
278                         pCppStack, pParamTypeDescr,
279                         pThis->getBridge()->getCpp2Uno() );
280                     pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
281                     // will be released at reconversion
282                     ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
283                 }
284                 else // direct way
285                 {
286                     pUnoArgs[nPos] = pCppStack;
287                     // no longer needed
288                     TYPELIB_DANGER_RELEASE( pParamTypeDescr );
289                 }
290             }
291         }
292 
293         // ExceptionHolder
294         uno_Any aUnoExc; // Any will be constructed by callee
295         uno_Any * pUnoExc = &aUnoExc;
296 
297 #ifdef CMC_DEBUG
298 	fprintf(stderr, "before dispatch\n");
299 #endif
300         // invoke uno dispatch call
301         (*pThis->getUnoI()->pDispatcher)(
302           pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
303 
304 #ifdef CMC_DEBUG
305 	fprintf(stderr, "after dispatch\n");
306 #endif
307 
308         // in case an exception occured...
309         if (pUnoExc)
310         {
311             // destruct temporary in/inout params
312             for ( ; nTempIndizes--; )
313             {
314                 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
315 
316                 if (pParams[nIndex].bIn) // is in/inout => was constructed
317                     uno_destructData( pUnoArgs[nIndex],
318                         ppTempParamTypeDescr[nTempIndizes], 0 );
319                 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
320             }
321             if (pReturnTypeDescr)
322                 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
323 
324             CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc,
325                 pThis->getBridge()->getUno2Cpp() ); // has to destruct the any
326             // is here for dummy
327             return typelib_TypeClass_VOID;
328         }
329         else // else no exception occured...
330         {
331             // temporary params
332             for ( ; nTempIndizes--; )
333             {
334                 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
335                 typelib_TypeDescription * pParamTypeDescr =
336                     ppTempParamTypeDescr[nTempIndizes];
337 
338                 if (pParams[nIndex].bOut) // inout/out
339                 {
340                     // convert and assign
341                     uno_destructData( pCppArgs[nIndex], pParamTypeDescr,
342                         cpp_release );
343                     uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex],
344                         pParamTypeDescr, 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,
357                         pReturnTypeDescr, pThis->getBridge()->getUno2Cpp() );
358                     // destroy temp uno return
359                     uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
360                 }
361                 // complex return ptr is set to eax
362                 *(void **)pRegisterReturn = pCppReturn;
363             }
364             if (pReturnTypeDescr)
365             {
366                 typelib_TypeClass eRet =
367                     (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
368                 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
369                 return eRet;
370             }
371             else
372                 return typelib_TypeClass_VOID;
373         }
374     }
375 
376 
377     //=====================================================================
378     static typelib_TypeClass cpp_mediate(
379         sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
380         void ** gpreg, double* fpreg,
381         long sp, long r8,
382         sal_Int64 * pRegisterReturn /* space for register return */ )
383 
384     {
385 	void ** ovrflw = (void**)(sp);
386 #ifdef CMC_DEBUG
387 	fprintf(stderr, "cpp_mediate with\n");
388 	fprintf(stderr, "%x %x\n", nFunctionIndex, nVtableOffset);
389 	fprintf(stderr, "and %x %x\n", (long)(ovrflw[0]), (long)(ovrflw[-1]));
390 	fprintf(stderr, "and %x %x\n", (long)(ovrflw[-2]), (long)(ovrflw[-3]));
391 	fprintf(stderr, "and %x %x\n", (long)(ovrflw[-4]), (long)(ovrflw[-5]));
392 	fprintf(stderr, "and %x %x\n", (long)(ovrflw[-6]), (long)(ovrflw[-7]));
393 	fprintf(stderr, "and %x %x\n", (long)(ovrflw[-8]), (long)(ovrflw[-9]));
394 	fprintf(stderr, "and %x %x\n", (long)(ovrflw[-10]), (long)(ovrflw[-11]));
395 	fprintf(stderr, "and %x %x\n", (long)(ovrflw[-12]), (long)(ovrflw[-13]));
396 	fprintf(stderr, "and %x %x\n", (long)(ovrflw[-14]), (long)(ovrflw[-15]));
397 #endif
398         OSL_ENSURE( sizeof(sal_Int32)==sizeof(void *), "### unexpected!" );
399 
400         // gpreg:  [ret *], this, [other gpr params]
401         // fpreg:  [fpr params]
402         // ovrflw: [gpr or fpr params (properly aligned)]
403 
404         void * pThis;
405         if (nFunctionIndex & 0x80000000 )
406         {
407 	    nFunctionIndex &= 0x7fffffff;
408 	    pThis = gpreg[1];
409 #ifdef CMC_DEBUG
410 	    fprintf(stderr, "pThis is gpreg[1]\n");
411 #endif
412         }
413         else
414         {
415 	    pThis = gpreg[0];
416 #ifdef CMC_DEBUG
417             fprintf(stderr, "pThis is gpreg[0]\n");
418 #endif
419         }
420 
421         pThis = static_cast< char * >(pThis) - nVtableOffset;
422 
423         bridges::cpp_uno::shared::CppInterfaceProxy * pCppI =
424             bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
425                 pThis);
426 
427         typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
428 
429         OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex,
430             "### illegal vtable index!" );
431         if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
432         {
433             throw RuntimeException(
434                 OUString::createFromAscii("illegal vtable index!"),
435                 (XInterface *)pCppI );
436         }
437 
438         // determine called method
439         OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex,
440             "### illegal vtable index!" );
441         sal_Int32 nMemberPos =
442             pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
443         OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers,
444             "### illegal member index!" );
445 
446         TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
447 
448         typelib_TypeClass eRet;
449         switch (aMemberDescr.get()->eTypeClass)
450         {
451         case typelib_TypeClass_INTERFACE_ATTRIBUTE:
452         {
453             if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] ==
454                 nFunctionIndex)
455             {
456                 // is GET method
457                 eRet = cpp2uno_call(
458                     pCppI, aMemberDescr.get(),
459                     ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef,
460                     0, 0, // no params
461                     r8, gpreg, fpreg, ovrflw, pRegisterReturn );
462             }
463             else
464             {
465                 // is SET method
466                 typelib_MethodParameter aParam;
467                 aParam.pTypeRef =
468                     ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef;
469                 aParam.bIn      = sal_True;
470                 aParam.bOut     = sal_False;
471 
472                 eRet = cpp2uno_call(
473                     pCppI, aMemberDescr.get(),
474                     0, // indicates void return
475                     1, &aParam,
476                     r8, gpreg, fpreg, ovrflw, pRegisterReturn );
477             }
478             break;
479         }
480         case typelib_TypeClass_INTERFACE_METHOD:
481         {
482             // is METHOD
483             switch (nFunctionIndex)
484             {
485             case 1: // acquire()
486                 pCppI->acquireProxy(); // non virtual call!
487                 eRet = typelib_TypeClass_VOID;
488                 break;
489             case 2: // release()
490                 pCppI->releaseProxy(); // non virtual call!
491                 eRet = typelib_TypeClass_VOID;
492                 break;
493             case 0: // queryInterface() opt
494             {
495                 typelib_TypeDescription * pTD = 0;
496                 TYPELIB_DANGER_GET(&pTD,
497                     reinterpret_cast<Type *>(gpreg[1])->getTypeLibType());
498                 if (pTD)
499                 {
500                     XInterface * pInterface = 0;
501                     (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
502                         pCppI->getBridge()->getCppEnv(),
503                         (void **)&pInterface, pCppI->getOid().pData,
504                         (typelib_InterfaceTypeDescription *)pTD );
505 
506                     if (pInterface)
507                     {
508                         ::uno_any_construct(
509                             reinterpret_cast< uno_Any * >( r8 ),
510                             &pInterface, pTD, cpp_acquire );
511                         pInterface->release();
512                         TYPELIB_DANGER_RELEASE( pTD );
513                         *(void **)pRegisterReturn = (void*)r8;
514                         eRet = typelib_TypeClass_ANY;
515                         break;
516                     }
517                     TYPELIB_DANGER_RELEASE( pTD );
518                 }
519             } // else perform queryInterface()
520             default:
521                 eRet = cpp2uno_call(
522                     pCppI, aMemberDescr.get(),
523                     ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef,
524                     ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams,
525                     ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams,
526                     r8, gpreg, fpreg, ovrflw, pRegisterReturn );
527             }
528             break;
529         }
530         default:
531         {
532             throw RuntimeException(
533                 OUString::createFromAscii("no member description found!"),
534                 (XInterface *)pCppI );
535             // is here for dummy
536             eRet = typelib_TypeClass_VOID;
537         }
538         }
539 
540         return eRet;
541     }
542 }
543 
544 //=======================================================================
545 /**
546  * is called on incoming vtable calls
547  * (called by asm snippets)
548  */
549 
550 sal_Int64 cpp_vtable_call( sal_uInt32 in0, sal_uInt32 in1, sal_uInt32 in2, sal_uInt32 in3, sal_uInt32 firstonstack )
551 {
552     register sal_Int32 r21 asm("r21");
553     register sal_Int32 r22 asm("r22");
554     register sal_Int32 r28 asm("r28");
555     sal_Int32 functionIndex = r21;
556     sal_Int32 vtableOffset = r22;
557     sal_Int32 r8 = r28;
558 
559     long sp = (long)&firstonstack;
560 
561     sal_uInt32 gpreg[hppa::MAX_GPR_REGS];
562     gpreg[0] = in0;
563     gpreg[1] = in1;
564     gpreg[2] = in2;
565     gpreg[3] = in3;
566 
567     float fpreg[hppa::MAX_SSE_REGS]; //todo
568     register float f0 asm("fr4"); fpreg[0] = f0;
569     register float f1 asm("fr5"); fpreg[1] = f1;
570     register float f2 asm("fr6"); fpreg[2] = f2;
571     register float f3 asm("fr7"); fpreg[3] = f3;
572 
573     double dpreg[hppa::MAX_SSE_REGS]; //todo
574     register double d0 asm("fr4"); dpreg[0] = d0;
575     register double d1 asm("fr5"); dpreg[1] = d1;
576     register double d2 asm("fr6"); dpreg[2] = d2;
577     register double d3 asm("fr7"); dpreg[3] = d3;
578 
579 
580 #ifdef CMC_DEBUG
581     fprintf(stderr, "got to cpp_vtable_call with %x %x\n", functionIndex, vtableOffset);
582     for (int i = 0; i < hppa::MAX_GPR_REGS; ++i)
583 	fprintf(stderr, "reg %d is %d %x\n", i, gpreg[i], gpreg[i]);
584     for (int i = 0; i < hppa::MAX_SSE_REGS; ++i)
585 	fprintf(stderr, "float reg %d is %f %x\n", i, fpreg[i], ((long*)fpreg)[i]);
586     for (int i = 0; i < 4; ++i)
587 	fprintf(stderr, "double reg %d is %f %llx\n", i, dpreg[i], ((long long*)dpreg)[i]);
588 #endif
589 
590     sal_Int64 nRegReturn;
591 
592     typelib_TypeClass aType =
593         cpp_mediate( functionIndex, vtableOffset, (void**)gpreg, dpreg, sp, r8, &nRegReturn);
594 
595     switch( aType )
596     {
597         case typelib_TypeClass_FLOAT:
598             f0 = (*((float*)&nRegReturn));
599             break;
600         case typelib_TypeClass_DOUBLE:
601             d0 = (*((double*)&nRegReturn));
602             break;
603         default:
604             break;
605     }
606 
607     return nRegReturn;
608 }
609 
610 
611 namespace
612 {
613     const int codeSnippetSize = 44;
614 
615 #   define unldil(v) (((v & 0x7c) << 14) | ((v & 0x180) << 7) | ((v & 0x3) << 12) | ((v & 0xffe00) >> 8) | ((v & 0x100000) >> 20))
616 #   define L21(v)  unldil(((unsigned long)(v) >> 11) & 0x1fffff) //Left 21 bits
617 #   define R11(v)  (((unsigned long)(v) & 0x7FF) << 1) //Right 11 bits
618 
619     unsigned char *codeSnippet(unsigned char* code, sal_Int32 functionIndex,
620         sal_Int32 vtableOffset, bool bHasHiddenParam)
621     {
622         if (bHasHiddenParam)
623             functionIndex |= 0x80000000;
624 
625         unsigned char * p = code;
626         *(unsigned long*)&p[0]  = 0xeaa00000; // b,l 0x8,r21
627         *(unsigned long*)&p[4]  = 0xd6a01c1e; // depwi 0,31,2,r21
628         *(unsigned long*)&p[8]  = 0x4aa10040; // ldw 32(r21),r1
629 
630         *(unsigned long*)&p[12] = 0x22A00000 | L21(functionIndex); // ldil L<functionIndex>,r21
631         *(unsigned long*)&p[16] = 0x36B50000 | R11(functionIndex); // ldo R<functionIndex>,r21
632 
633         *(unsigned long*)&p[20] = 0x22C00000 | L21(vtableOffset); // ldil L<vtableOffset>,r22
634         *(unsigned long*)&p[24] = 0x36D60000 | R11(vtableOffset); // ldo R<vtableOffset>,r22
635 
636         *(unsigned long*)&p[28] = 0x0c201094; // ldw 0(r1),r20
637         *(unsigned long*)&p[32] = 0xea80c000; // bv r0(r20)
638         *(unsigned long*)&p[36] = 0x0c281093; // ldw 4(r1),r19
639         *(unsigned long*)&p[40] = ((unsigned long)(cpp_vtable_call) & ~2);
640 
641         return code + codeSnippetSize;
642     }
643 }
644 
645 struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; };
646 
647 bridges::cpp_uno::shared::VtableFactory::Slot *
648 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
649 {
650     return static_cast< Slot * >(block) + 2;
651 }
652 
653 sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize(
654     sal_Int32 slotCount)
655 {
656     return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
657 }
658 
659 bridges::cpp_uno::shared::VtableFactory::Slot *
660 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
661     void * block, sal_Int32 slotCount)
662 {
663     Slot * slots = mapBlockToVtable(block);
664     slots[-2].fn = 0;
665     slots[-1].fn = 0;
666     return slots + slotCount;
667 }
668 
669 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
670     Slot ** slots, unsigned char * code, sal_PtrDiff writetoexecdiff,
671     typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
672     sal_Int32 functionCount, sal_Int32 vtableOffset)
673 {
674     (*slots) -= functionCount;
675     Slot * s = *slots;
676     for (sal_Int32 i = 0; i < type->nMembers; ++i)
677     {
678         typelib_TypeDescription * member = 0;
679         TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
680         OSL_ASSERT(member != 0);
681         switch (member->eTypeClass)
682         {
683             case typelib_TypeClass_INTERFACE_ATTRIBUTE:
684                 // Getter:
685                 (s++)->fn = code + writetoexecdiff;
686                 code = codeSnippet(code, functionOffset++, vtableOffset, false);
687                 // Setter:
688                 if (!reinterpret_cast<
689                     typelib_InterfaceAttributeTypeDescription * >(
690                         member)->bReadOnly)
691                 {
692                     (s++)->fn = code + writetoexecdiff;
693                     code = codeSnippet(code, functionOffset++, vtableOffset, false);
694                 }
695                 break;
696             case typelib_TypeClass_INTERFACE_METHOD:
697             {
698                 (s++)->fn = code + writetoexecdiff;
699                 code = codeSnippet(code, functionOffset++, vtableOffset, false);
700                 break;
701             }
702         default:
703             OSL_ASSERT(false);
704             break;
705         }
706         TYPELIB_DANGER_RELEASE(member);
707     }
708     return code;
709 }
710 
711 void bridges::cpp_uno::shared::VtableFactory::flushCode(
712     unsigned char const *beg, unsigned char const *end)
713 {
714     void *p = (void*)((size_t)beg & ~31);
715     size_t stride = 32;
716     while (p < end)
717     {
718         asm volatile("fdc (%0)\n\t"
719                      "sync\n\t"
720                      "fic,m %1(%%sr4, %0)\n\t"
721                      "sync" : "+r"(p) : "r"(stride) : "memory");
722     }
723 }
724 
725 /* vi:set tabstop=4 shiftwidth=4 expandtab: */
726