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