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