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, ¶m, 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