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 "precompiled_bridges.hxx"
25 #include "sal/config.h"
26 
27 #include <cstddef>
28 #include <cstdlib>
29 #include <cstring>
30 
31 #include "bridges/cpp_uno/shared/bridge.hxx"
32 #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx"
33 #include "bridges/cpp_uno/shared/types.hxx"
34 #include "bridges/cpp_uno/shared/vtablefactory.hxx"
35 #include "com/sun/star/uno/genfunc.hxx"
36 #include "osl/diagnose.h"
37 #include "sal/alloca.h"
38 #include "sal/types.h"
39 #include "typelib/typeclass.h"
40 #include "typelib/typedescription.h"
41 #include "typelib/typedescription.hxx"
42 #include "uno/any2.h"
43 #include "uno/data.h"
44 
45 #include "exceptions.hxx"
46 #include "flushcode.hxx"
47 #include "fp.hxx"
48 #include "isdirectreturntype.hxx"
49 #include "vtableslotcall.hxx"
50 
51 namespace {
52 
53 namespace css = com::sun::star;
54 
loadFpRegsFromStruct(typelib_TypeDescription * type,void * data)55 void loadFpRegsFromStruct(typelib_TypeDescription * type, void * data) {
56     for (typelib_CompoundTypeDescription * t =
57              reinterpret_cast< typelib_CompoundTypeDescription * >(type);
58          t != NULL; t = t->pBaseTypeDescription)
59     {
60         for (sal_Int32 i = 0; i < t->nMembers; ++i) {
61             switch (t->ppTypeRefs[i]->eTypeClass) {
62             case typelib_TypeClass_FLOAT:
63                 switch (t->pMemberOffsets[i]) {
64                 case 0:
65                     fp_loadf0(reinterpret_cast< float * >(data));
66                     break;
67                 case 4:
68                     fp_loadf1(reinterpret_cast< float * >(data) + 1);
69                     break;
70                 case 8:
71                     fp_loadf2(reinterpret_cast< float * >(data) + 2);
72                     break;
73                 case 12:
74                     fp_loadf3(reinterpret_cast< float * >(data) + 3);
75                     break;
76                 case 16:
77                     fp_loadf4(reinterpret_cast< float * >(data) + 4);
78                     break;
79                 case 20:
80                     fp_loadf5(reinterpret_cast< float * >(data) + 5);
81                     break;
82                 case 24:
83                     fp_loadf6(reinterpret_cast< float * >(data) + 6);
84                     break;
85                 case 28:
86                     fp_loadf7(reinterpret_cast< float * >(data) + 7);
87                     break;
88                 default:
89                     OSL_ASSERT(false);
90                     break;
91                 }
92                 break;
93             case typelib_TypeClass_DOUBLE:
94                 switch (t->pMemberOffsets[i]) {
95                 case 0:
96                     fp_loadd0(reinterpret_cast< double * >(data));
97                     break;
98                 case 8:
99                     fp_loadd2(reinterpret_cast< double * >(data) + 1);
100                     break;
101                 case 16:
102                     fp_loadd4(reinterpret_cast< double * >(data) + 2);
103                     break;
104                 case 24:
105                     fp_loadd6(reinterpret_cast< double * >(data) + 3);
106                     break;
107                 default:
108                     OSL_ASSERT(false);
109                     break;
110                 }
111                 break;
112             case typelib_TypeClass_STRUCT:
113                 {
114                     typelib_TypeDescription * td = NULL;
115                     TYPELIB_DANGER_GET(&td, t->ppTypeRefs[i]);
116                     loadFpRegsFromStruct(td, data);
117                     TYPELIB_DANGER_RELEASE(td);
118                     break;
119                 }
120             }
121         }
122     }
123 }
124 
call(bridges::cpp_uno::shared::CppInterfaceProxy * proxy,css::uno::TypeDescription const & description,bool directReturn,typelib_TypeDescriptionReference * returnType,sal_Int32 count,typelib_MethodParameter * parameters,unsigned long * callStack)125 void call(
126     bridges::cpp_uno::shared::CppInterfaceProxy * proxy,
127     css::uno::TypeDescription const & description,
128     bool directReturn, typelib_TypeDescriptionReference * returnType,
129     sal_Int32 count, typelib_MethodParameter * parameters,
130     unsigned long * callStack)
131 {
132     typelib_TypeDescription * rtd = NULL;
133     if (returnType != NULL) {
134         TYPELIB_DANGER_GET(&rtd, returnType);
135     }
136     bool retconv =
137         rtd != NULL && bridges::cpp_uno::shared::relatesToInterfaceType(rtd);
138     OSL_ASSERT(!(directReturn && retconv));
139     void * retin;
140     void * retout;
141     char retbuf[32];
142     if (directReturn) {
143         retin = returnType == NULL ? NULL : retbuf;
144     } else {
145         retout = reinterpret_cast< void * >(callStack[0]);
146         retin = retconv ? alloca(rtd->nSize) : retout;
147     }
148     void ** args = static_cast< void ** >(alloca(count * sizeof (void *)));
149     void ** cppArgs = static_cast< void ** >(alloca(count * sizeof (void *)));
150     typelib_TypeDescription ** argtds =
151         static_cast< typelib_TypeDescription ** >(
152             alloca(count * sizeof (typelib_TypeDescription *)));
153     union fp { float f; double d; };
154     fp copies[15];
155     sal_Int32 stackPos = directReturn ? 1 : 2; // skip return ptr and this ptr
156     for (sal_Int32 i = 0; i < count; ++i) {
157         typelib_TypeDescription * ptd = NULL;
158         TYPELIB_DANGER_GET(&ptd, parameters[i].pTypeRef);
159         if (!parameters[i].bOut && bridges::cpp_uno::shared::isSimpleType(ptd))
160         {
161             switch (ptd->eTypeClass) {
162             case typelib_TypeClass_FLOAT:
163                 if (stackPos <= 15) {
164                     switch (stackPos) {
165                     case 1:
166                         fp_storef3(&copies[0].f);
167                         break;
168                     case 2:
169                         fp_storef5(&copies[1].f);
170                         break;
171                     case 3:
172                         fp_storef7(&copies[2].f);
173                         break;
174                     case 4:
175                         fp_storef9(&copies[3].f);
176                         break;
177                     case 5:
178                         fp_storef11(&copies[4].f);
179                         break;
180                     case 6:
181                         fp_storef13(&copies[5].f);
182                         break;
183                     case 7:
184                         fp_storef15(&copies[6].f);
185                         break;
186                     case 8:
187                         fp_storef17(&copies[7].f);
188                         break;
189                     case 9:
190                         fp_storef19(&copies[8].f);
191                         break;
192                     case 10:
193                         fp_storef21(&copies[9].f);
194                         break;
195                     case 11:
196                         fp_storef23(&copies[10].f);
197                         break;
198                     case 12:
199                         fp_storef25(&copies[11].f);
200                         break;
201                     case 13:
202                         fp_storef27(&copies[12].f);
203                         break;
204                     case 14:
205                         fp_storef29(&copies[13].f);
206                         break;
207                     case 15:
208                         fp_storef31(&copies[14].f);
209                         break;
210                     default:
211                         OSL_ASSERT(false);
212                         break;
213                     }
214                     args[i] = &copies[stackPos - 1].f;
215                 } else {
216                     args[i] = reinterpret_cast< char * >(callStack + stackPos) +
217                         (sizeof (unsigned long) - sizeof (float));
218                 }
219                 break;
220             case typelib_TypeClass_DOUBLE:
221                 if (stackPos <= 15) {
222                     switch (stackPos) {
223                     case 1:
224                         fp_stored2(&copies[0].d);
225                         break;
226                     case 2:
227                         fp_stored4(&copies[1].d);
228                         break;
229                     case 3:
230                         fp_stored6(&copies[2].d);
231                         break;
232                     case 4:
233                         fp_stored8(&copies[3].d);
234                         break;
235                     case 5:
236                         fp_stored10(&copies[4].d);
237                         break;
238                     case 6:
239                         fp_stored12(&copies[5].d);
240                         break;
241                     case 7:
242                         fp_stored14(&copies[6].d);
243                         break;
244                     case 8:
245                         fp_stored16(&copies[7].d);
246                         break;
247                     case 9:
248                         fp_stored18(&copies[8].d);
249                         break;
250                     case 10:
251                         fp_stored20(&copies[9].d);
252                         break;
253                     case 11:
254                         fp_stored22(&copies[10].d);
255                         break;
256                     case 12:
257                         fp_stored24(&copies[11].d);
258                         break;
259                     case 13:
260                         fp_stored26(&copies[12].d);
261                         break;
262                     case 14:
263                         fp_stored28(&copies[13].d);
264                         break;
265                     case 15:
266                         fp_stored30(&copies[14].d);
267                         break;
268                     default:
269                         OSL_ASSERT(false);
270                         break;
271                     }
272                     args[i] = &copies[stackPos - 1].d;
273                 } else {
274                     args[i] = reinterpret_cast< char * >(callStack + stackPos) +
275                         (sizeof (unsigned long) - sizeof (double));
276                 }
277                 break;
278             default:
279                 OSL_ASSERT(ptd->nSize <= 8);
280                 args[i] = reinterpret_cast< char * >(callStack + stackPos) +
281                     (sizeof (unsigned long) - ptd->nSize);
282                 break;
283             }
284             argtds[i] = NULL;
285             TYPELIB_DANGER_RELEASE(ptd);
286         } else {
287             cppArgs[i] = reinterpret_cast< void * >(callStack[stackPos]);
288             if (!parameters[i].bIn) {
289                 args[i] = alloca(ptd->nSize);
290                 argtds[i] = ptd;
291             } else if (bridges::cpp_uno::shared::relatesToInterfaceType(ptd)) {
292                 args[i] = alloca(ptd->nSize);
293                 uno_copyAndConvertData(
294                     args[i], reinterpret_cast< void * >(callStack[stackPos]),
295                     ptd, proxy->getBridge()->getCpp2Uno());
296                 argtds[i] = ptd;
297             } else {
298                 args[i] = reinterpret_cast< void * >(callStack[stackPos]);
299                 argtds[i] = NULL;
300                 TYPELIB_DANGER_RELEASE(ptd);
301             }
302         }
303         ++stackPos;
304     }
305     uno_Any exc;
306     uno_Any * pexc = &exc;
307     proxy->getUnoI()->pDispatcher(
308         proxy->getUnoI(), description.get(), retin, args, &pexc);
309     if (pexc != NULL) {
310         for (sal_Int32 i = 0; i < count; ++i) {
311             if (argtds[i] != NULL) {
312                 if (parameters[i].bIn) {
313                     uno_destructData(args[i], argtds[i], NULL);
314                 }
315                 TYPELIB_DANGER_RELEASE(argtds[i]);
316             }
317         }
318         if (rtd != NULL) {
319             TYPELIB_DANGER_RELEASE(rtd);
320         }
321         bridges::cpp_uno::cc5_solaris_sparc64::raiseException(
322             &exc, proxy->getBridge()->getUno2Cpp());
323         std::abort(); // just in case
324     }
325     for (sal_Int32 i = 0; i < count; ++i) {
326         if (argtds[i] != NULL) {
327             if (parameters[i].bOut) {
328                 uno_destructData(
329                     cppArgs[i], argtds[i],
330                     reinterpret_cast< uno_ReleaseFunc >(css::uno::cpp_release));
331                 uno_copyAndConvertData(
332                     cppArgs[i], args[i], argtds[i],
333                     proxy->getBridge()->getUno2Cpp());
334             }
335             uno_destructData(args[i], argtds[i], NULL);
336             TYPELIB_DANGER_RELEASE(argtds[i]);
337         }
338     }
339     if (directReturn) {
340         if (rtd != NULL) {
341             switch (rtd->eTypeClass) {
342             case typelib_TypeClass_VOID:
343                 break;
344             case typelib_TypeClass_BOOLEAN:
345                 callStack[0] = *reinterpret_cast< sal_Bool * >(retbuf);
346                 break;
347             case typelib_TypeClass_BYTE:
348                 callStack[0] = *reinterpret_cast< sal_Int8 * >(retbuf);
349                 break;
350             case typelib_TypeClass_SHORT:
351                 callStack[0] = *reinterpret_cast< sal_Int16 * >(retbuf);
352                 break;
353             case typelib_TypeClass_UNSIGNED_SHORT:
354                 callStack[0] = *reinterpret_cast< sal_uInt16 * >(retbuf);
355                 break;
356             case typelib_TypeClass_LONG:
357             case typelib_TypeClass_ENUM:
358                 callStack[0] = *reinterpret_cast< sal_Int32 * >(retbuf);
359                 break;
360             case typelib_TypeClass_UNSIGNED_LONG:
361                 callStack[0] = *reinterpret_cast< sal_uInt32 * >(retbuf);
362                 break;
363             case typelib_TypeClass_HYPER:
364                 callStack[0] = *reinterpret_cast< sal_Int64 * >(retbuf);
365                 break;
366             case typelib_TypeClass_UNSIGNED_HYPER:
367                 callStack[0] = *reinterpret_cast< sal_uInt64 * >(retbuf);
368                 break;
369             case typelib_TypeClass_FLOAT:
370                 fp_loadf0(reinterpret_cast< float * >(retbuf));
371                 break;
372             case typelib_TypeClass_DOUBLE:
373                 fp_loadd0(reinterpret_cast< double * >(retbuf));
374                 break;
375             case typelib_TypeClass_CHAR:
376                 callStack[0] = *reinterpret_cast< sal_Unicode * >(retbuf);
377                 break;
378             case typelib_TypeClass_STRING:
379             case typelib_TypeClass_TYPE:
380             case typelib_TypeClass_SEQUENCE:
381             case typelib_TypeClass_INTERFACE:
382                 callStack[0] = reinterpret_cast< unsigned long >(
383                     *reinterpret_cast< void ** >(retbuf));
384                 break;
385             case typelib_TypeClass_STRUCT:
386                 loadFpRegsFromStruct(rtd, retbuf);
387                 // fall through
388             case typelib_TypeClass_ANY:
389                 std::memcpy(callStack, retbuf, rtd->nSize);
390                 break;
391             default:
392                 OSL_ASSERT(false);
393                 break;
394             }
395         }
396     } else if (retconv) {
397         uno_copyAndConvertData(
398             retout, retin, rtd, proxy->getBridge()->getUno2Cpp());
399         uno_destructData(retin, rtd, NULL);
400     }
401     if (rtd != NULL) {
402         TYPELIB_DANGER_RELEASE(rtd);
403     }
404 }
405 
vtableCall(sal_Int32 functionIndex,sal_Int32 vtableOffset,unsigned long * callStack)406 extern "C" void vtableCall(
407     sal_Int32 functionIndex, sal_Int32 vtableOffset, unsigned long * callStack)
408 {
409     bool direct = static_cast< sal_uInt32 >((functionIndex) & 0x80000000) == 0;
410     functionIndex = static_cast< sal_uInt32 >(functionIndex) & 0x7FFFFFFF;
411     bridges::cpp_uno::shared::CppInterfaceProxy * proxy
412         = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
413             reinterpret_cast< char * >(callStack[direct ? 0 : 1]) -
414             vtableOffset);
415     typelib_InterfaceTypeDescription * type = proxy->getTypeDescr();
416     OSL_ASSERT(functionIndex < type->nMapFunctionIndexToMemberIndex);
417     sal_Int32 pos = type->pMapFunctionIndexToMemberIndex[functionIndex];
418     css::uno::TypeDescription desc(type->ppAllMembers[pos]);
419     switch (desc.get()->eTypeClass) {
420     case typelib_TypeClass_INTERFACE_ATTRIBUTE:
421         if (type->pMapMemberIndexToFunctionIndex[pos] == functionIndex) {
422             // Getter:
423             call(
424                 proxy, desc, direct,
425                 reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >(
426                     desc.get())->pAttributeTypeRef,
427                 0, NULL, callStack);
428         } else {
429             // Setter:
430             typelib_MethodParameter param = {
431                 NULL,
432                 reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >(
433                     desc.get())->pAttributeTypeRef,
434                 true, false };
435             call(proxy, desc, true, NULL, 1, &param, callStack);
436         }
437         break;
438     case typelib_TypeClass_INTERFACE_METHOD:
439         switch (functionIndex) {
440         case 1:
441             proxy->acquireProxy();
442             break;
443         case 2:
444             proxy->releaseProxy();
445             break;
446         case 0:
447             {
448                 typelib_TypeDescription * td = NULL;
449                 TYPELIB_DANGER_GET(
450                     &td,
451                     reinterpret_cast< css::uno::Type * >(
452                         callStack[2])->getTypeLibType());
453                 if (td != NULL) {
454                     css::uno::XInterface * ifc = NULL;
455                     proxy->getBridge()->getCppEnv()->getRegisteredInterface(
456                         proxy->getBridge()->getCppEnv(),
457                         reinterpret_cast< void ** >(&ifc),
458                         proxy->getOid().pData,
459                         reinterpret_cast< typelib_InterfaceTypeDescription * >(
460                             td));
461                     if (ifc != NULL) {
462                         uno_any_construct(
463                             reinterpret_cast< uno_Any * >(callStack[0]), &ifc,
464                             td,
465                             reinterpret_cast< uno_AcquireFunc >(
466                                 css::uno::cpp_acquire));
467                         ifc->release();
468                         TYPELIB_DANGER_RELEASE(td);
469                         break;
470                     }
471                     TYPELIB_DANGER_RELEASE(td);
472                 }
473             } // fall through
474         default:
475             call(
476                 proxy, desc, direct,
477                 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
478                     desc.get())->pReturnTypeRef,
479                 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
480                     desc.get())->nParams,
481                 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
482                     desc.get())->pParams,
483                 callStack);
484         }
485         break;
486     default:
487         OSL_ASSERT(false);
488         break;
489     }
490 }
491 
492 int const codeSnippetSize = 10 * 4;
493 
generateCodeSnippet(unsigned char * code,sal_Int32 functionIndex,sal_Int32 vtableOffset,bool directReturn)494 unsigned char * generateCodeSnippet(
495     unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset,
496     bool directReturn)
497 {
498     sal_uInt32 index = functionIndex;
499     if (!directReturn) {
500         index |= 0x80000000;
501     }
502     unsigned int * p = reinterpret_cast< unsigned int * >(code);
503     OSL_ASSERT(sizeof (unsigned int) == 4);
504     // 0*4: save %sp, -176, %sp ! minimal stack frame:
505     *p++ = 0x9DE3BF50;
506     // 1*4: rd %pc, %l0:
507     *p++ = 0xA1414000;
508     // 2*4: ldx %l0, (8-1)*4, %l0:
509     *p++ = 0xE05C201C;
510     // 3*4: sethi %hi(index), %o0:
511     *p++ = 0x11000000 | (index >> 10);
512     // 4*4: or %o0, %lo(index), %o0:
513     *p++ = 0x90122000 | (index & 0x3FF);
514     // 5*4: sethi %hi(vtableOffset), %o1:
515     *p++ = 0x13000000 | (vtableOffset >> 10);
516     // 6*4: jmpl %l0, %g0, %g0:
517     *p++ = 0x81C40000;
518     // 7*4: or %o1, %lo(vtableOffset), %o1:
519     *p++ = 0x92126000 | (vtableOffset & 0x3FF);
520     // 8*4: .xword privateSnippetExecutor:
521     *reinterpret_cast< unsigned long * >(p) =
522         reinterpret_cast< unsigned long >(vtableSlotCall);
523     return code + codeSnippetSize;
524 }
525 
526 }
527 
528 struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; };
529 
530 bridges::cpp_uno::shared::VtableFactory::Slot *
mapBlockToVtable(void * block)531 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) {
532     return static_cast< Slot * >(block) + 1;
533 }
534 
getBlockSize(sal_Int32 slotCount)535 sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize(
536     sal_Int32 slotCount)
537 {
538     return (slotCount + 3) * sizeof (Slot) + slotCount * codeSnippetSize;
539 }
540 
541 bridges::cpp_uno::shared::VtableFactory::Slot *
initializeBlock(void * block,sal_Int32 slotCount)542 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
543     void * block, sal_Int32 slotCount)
544 {
545     Slot * slots = mapBlockToVtable(block) + 2;
546     slots[-3].fn = NULL; // RTTI
547     slots[-2].fn = NULL; // null
548     slots[-1].fn = NULL; // destructor
549     return slots + slotCount;
550 }
551 
addLocalFunctions(Slot ** slots,unsigned char * code,typelib_InterfaceTypeDescription const * type,sal_Int32 functionOffset,sal_Int32 functionCount,sal_Int32 vtableOffset)552 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
553     Slot ** slots, unsigned char * code,
554     typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
555     sal_Int32 functionCount, sal_Int32 vtableOffset)
556 {
557     (*slots) -= functionCount;
558     Slot * s = *slots;
559     for (sal_Int32 i = 0; i < type->nMembers; ++i) {
560         typelib_TypeDescription * member = 0;
561         TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
562         OSL_ASSERT(member != 0);
563         switch (member->eTypeClass) {
564         case typelib_TypeClass_INTERFACE_ATTRIBUTE:
565             // Getter:
566             (s++)->fn = code;
567             code = generateCodeSnippet(
568                 code, functionOffset++, vtableOffset,
569                 bridges::cpp_uno::cc5_solaris_sparc64::isDirectReturnType(
570                     reinterpret_cast<
571                     typelib_InterfaceAttributeTypeDescription * >(
572                         member)->pAttributeTypeRef));
573             // Setter:
574             if (!reinterpret_cast<
575                 typelib_InterfaceAttributeTypeDescription * >(
576                     member)->bReadOnly)
577             {
578                 (s++)->fn = code;
579                 code = generateCodeSnippet(
580                     code, functionOffset++, vtableOffset, true);
581             }
582             break;
583 
584         case typelib_TypeClass_INTERFACE_METHOD:
585             (s++)->fn = code;
586             code = generateCodeSnippet(
587                 code, functionOffset++, vtableOffset,
588                 bridges::cpp_uno::cc5_solaris_sparc64::isDirectReturnType(
589                     reinterpret_cast<
590                     typelib_InterfaceMethodTypeDescription * >(
591                         member)->pReturnTypeRef));
592             break;
593 
594         default:
595             OSL_ASSERT(false);
596             break;
597         }
598         TYPELIB_DANGER_RELEASE(member);
599     }
600     return code;
601 }
602 
flushCode(unsigned char const * begin,unsigned char const * end)603 void bridges::cpp_uno::shared::VtableFactory::flushCode(
604     unsigned char const * begin, unsigned char const * end)
605 {
606     bridges::cpp_uno::cc5_solaris_sparc64::flushCode(begin, end);
607 }
608