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