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 <stdlib.h>
25 #include <hash_map>
26
27 #include <rtl/alloc.h>
28 #include <osl/mutex.hxx>
29
30 #include <com/sun/star/uno/genfunc.hxx>
31 #include "com/sun/star/uno/RuntimeException.hpp"
32 #include <uno/data.h>
33 #include <typelib/typedescription.hxx>
34
35 #include "bridges/cpp_uno/shared/bridge.hxx"
36 #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx"
37 #include "bridges/cpp_uno/shared/types.hxx"
38 #include "bridges/cpp_uno/shared/vtablefactory.hxx"
39
40 #include "share.hxx"
41
42 #include <dlfcn.h>
43
44
45 using namespace ::osl;
46 using namespace ::rtl;
47 using namespace ::com::sun::star::uno;
48
49 namespace
50 {
51
cpp2uno_call(bridges::cpp_uno::shared::CppInterfaceProxy * pThis,const typelib_TypeDescription * pMemberTypeDescr,typelib_TypeDescriptionReference * pReturnTypeRef,sal_Int32 nParams,typelib_MethodParameter * pParams,void ** pCallStack,sal_Int64 * pRegisterReturn)52 static typelib_TypeClass cpp2uno_call(
53 bridges::cpp_uno::shared::CppInterfaceProxy* pThis,
54 const typelib_TypeDescription * pMemberTypeDescr,
55 typelib_TypeDescriptionReference * pReturnTypeRef,
56 sal_Int32 nParams, typelib_MethodParameter * pParams,
57 void ** pCallStack,
58 sal_Int64 * pRegisterReturn /* space for register return */ )
59 {
60 // pCallStack: ret, [return ptr], this, params
61 char * pTopStack = (char *)(pCallStack + 0);
62 char * pCppStack = pTopStack;
63
64 // return
65 typelib_TypeDescription * pReturnTypeDescr = 0;
66 if (pReturnTypeRef)
67 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
68
69 void * pUnoReturn = 0;
70 // complex return ptr: if != 0 && != pUnoReturn, reconversion need
71 void * pCppReturn = 0;
72
73 if (pReturnTypeDescr)
74 {
75 if (!arm::return_in_hidden_param(pReturnTypeRef))
76 pUnoReturn = pRegisterReturn; // direct way for simple types
77 else // complex return via ptr (pCppReturn)
78 {
79 pCppReturn = *(void **)pCppStack;
80 pCppStack += sizeof(void *);
81
82 pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType(
83 pReturnTypeDescr )
84 ? alloca( pReturnTypeDescr->nSize )
85 : pCppReturn); // direct way
86 }
87 }
88 // pop this
89 pCppStack += sizeof( void* );
90
91 // stack space
92 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32),
93 "### unexpected size!" );
94 // parameters
95 void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams );
96 void ** pCppArgs = pUnoArgs + nParams;
97 // indizes of values this have to be converted (interface conversion
98 // cpp<=>uno)
99 sal_Int32 * pTempIndizes = (sal_Int32 *)(pUnoArgs + (2 * nParams));
100 // type descriptions for reconversions
101 typelib_TypeDescription ** ppTempParamTypeDescr =
102 (typelib_TypeDescription **)(pUnoArgs + (3 * nParams));
103
104 sal_Int32 nTempIndizes = 0;
105
106 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
107 {
108 const typelib_MethodParameter & rParam = pParams[nPos];
109 typelib_TypeDescription * pParamTypeDescr = 0;
110 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
111
112 if (!rParam.bOut &&
113 bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
114 {
115 #ifdef __ARM_EABI__
116 switch (pParamTypeDescr->eTypeClass)
117 {
118 case typelib_TypeClass_HYPER:
119 case typelib_TypeClass_UNSIGNED_HYPER:
120 case typelib_TypeClass_DOUBLE:
121 if ((pCppStack - pTopStack) % 8) pCppStack+=sizeof(sal_Int32); //align to 8
122 break;
123 default:
124 break;
125 }
126 #endif
127
128 pCppArgs[nPos] = pCppStack;
129 pUnoArgs[nPos] = pCppStack;
130 switch (pParamTypeDescr->eTypeClass)
131 {
132 case typelib_TypeClass_HYPER:
133 case typelib_TypeClass_UNSIGNED_HYPER:
134 case typelib_TypeClass_DOUBLE:
135 pCppStack += sizeof(sal_Int32); // extra long
136 break;
137 default:
138 break;
139 }
140 // no longer needed
141 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
142 }
143 else // ptr to complex value | ref
144 {
145 pCppArgs[nPos] = *(void **)pCppStack;
146
147 if (! rParam.bIn) // is pure out
148 {
149 // uno out is unconstructed mem!
150 pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
151 pTempIndizes[nTempIndizes] = nPos;
152 // will be released at reconversion
153 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
154 }
155 // is in/inout
156 else if (bridges::cpp_uno::shared::relatesToInterfaceType(
157 pParamTypeDescr ))
158 {
159 uno_copyAndConvertData( pUnoArgs[nPos] =
160 alloca( pParamTypeDescr->nSize ),
161 *(void **)pCppStack, pParamTypeDescr,
162 pThis->getBridge()->getCpp2Uno() );
163 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
164 // will be released at reconversion
165 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
166 }
167 else // direct way
168 {
169 pUnoArgs[nPos] = *(void **)pCppStack;
170 // no longer needed
171 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
172 }
173 }
174 pCppStack += sizeof(sal_Int32); // standard parameter length
175 }
176
177 // ExceptionHolder
178 uno_Any aUnoExc; // Any will be constructed by callee
179 uno_Any * pUnoExc = &aUnoExc;
180
181 // invoke uno dispatch call
182 (*pThis->getUnoI()->pDispatcher)(
183 pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
184
185 // in case an exception occurred...
186 if (pUnoExc)
187 {
188 // destruct temporary in/inout params
189 for ( ; nTempIndizes--; )
190 {
191 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
192
193 if (pParams[nIndex].bIn) // is in/inout => was constructed
194 uno_destructData( pUnoArgs[nIndex],
195 ppTempParamTypeDescr[nTempIndizes], 0 );
196 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
197 }
198 if (pReturnTypeDescr)
199 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
200
201 CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc,
202 pThis->getBridge()->getUno2Cpp() ); // has to destruct the any
203 // is here for dummy
204 return typelib_TypeClass_VOID;
205 }
206 else // else no exception occurred...
207 {
208 // temporary params
209 for ( ; nTempIndizes--; )
210 {
211 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
212 typelib_TypeDescription * pParamTypeDescr =
213 ppTempParamTypeDescr[nTempIndizes];
214
215 if (pParams[nIndex].bOut) // inout/out
216 {
217 // convert and assign
218 uno_destructData( pCppArgs[nIndex], pParamTypeDescr,
219 cpp_release );
220 uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex],
221 pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
222 }
223 // destroy temp uno param
224 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
225
226 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
227 }
228 // return
229 if (pCppReturn) // has complex return
230 {
231 if (pUnoReturn != pCppReturn) // needs reconversion
232 {
233 uno_copyAndConvertData( pCppReturn, pUnoReturn,
234 pReturnTypeDescr, pThis->getBridge()->getUno2Cpp() );
235 // destroy temp uno return
236 uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
237 }
238 // complex return ptr is set to eax
239 *(void **)pRegisterReturn = pCppReturn;
240 }
241 if (pReturnTypeDescr)
242 {
243 typelib_TypeClass eRet =
244 (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
245 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
246 return eRet;
247 }
248 else
249 return typelib_TypeClass_VOID;
250 }
251 }
252
253
254 //=====================================================================
cpp_mediate(sal_Int32 nFunctionIndex,sal_Int32 nVtableOffset,void ** pCallStack,sal_Int64 * pRegisterReturn)255 static typelib_TypeClass cpp_mediate(
256 sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
257 void ** pCallStack,
258 sal_Int64 * pRegisterReturn /* space for register return */ )
259 {
260 OSL_ENSURE( sizeof(sal_Int32)==sizeof(void *), "### unexpected!" );
261
262 // pCallStack: [ret *], this, params
263 // _this_ ptr is patched cppu_XInterfaceProxy object
264 void *pThis;
265 if( nFunctionIndex & 0x80000000 )
266 {
267 nFunctionIndex &= 0x7fffffff;
268 pThis = pCallStack[1];
269 }
270 else
271 {
272 pThis = pCallStack[0];
273 }
274
275 pThis = static_cast< char * >(pThis) - nVtableOffset;
276 bridges::cpp_uno::shared::CppInterfaceProxy * pCppI =
277 bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
278 pThis);
279
280 typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
281
282 OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex,
283 "### illegal vtable index!" );
284 if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
285 {
286 throw RuntimeException(
287 OUString::createFromAscii("illegal vtable index!"),
288 (XInterface *)pCppI );
289 }
290
291 // determine called method
292 OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex,
293 "### illegal vtable index!" );
294 sal_Int32 nMemberPos =
295 pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
296 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers,
297 "### illegal member index!" );
298
299 TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
300
301 typelib_TypeClass eRet;
302 switch (aMemberDescr.get()->eTypeClass)
303 {
304 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
305 {
306 if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] ==
307 nFunctionIndex)
308 {
309 // is GET method
310 eRet = cpp2uno_call(
311 pCppI, aMemberDescr.get(),
312 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef,
313 0, 0, // no params
314 pCallStack, pRegisterReturn );
315 }
316 else
317 {
318 // is SET method
319 typelib_MethodParameter aParam;
320 aParam.pTypeRef =
321 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef;
322 aParam.bIn = sal_True;
323 aParam.bOut = sal_False;
324
325 eRet = cpp2uno_call(
326 pCppI, aMemberDescr.get(),
327 0, // indicates void return
328 1, &aParam,
329 pCallStack, pRegisterReturn );
330 }
331 break;
332 }
333 case typelib_TypeClass_INTERFACE_METHOD:
334 {
335 // is METHOD
336 switch (nFunctionIndex)
337 {
338 case 1: // acquire()
339 pCppI->acquireProxy(); // non virtual call!
340 eRet = typelib_TypeClass_VOID;
341 break;
342 case 2: // release()
343 pCppI->releaseProxy(); // non virtual call!
344 eRet = typelib_TypeClass_VOID;
345 break;
346 case 0: // queryInterface() opt
347 {
348 typelib_TypeDescription * pTD = 0;
349 TYPELIB_DANGER_GET(&pTD,
350 reinterpret_cast<Type *>(pCallStack[2])->getTypeLibType());
351 if (pTD)
352 {
353 XInterface * pInterface = 0;
354 (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
355 pCppI->getBridge()->getCppEnv(),
356 (void **)&pInterface, pCppI->getOid().pData,
357 (typelib_InterfaceTypeDescription *)pTD );
358
359 if (pInterface)
360 {
361 ::uno_any_construct(
362 reinterpret_cast< uno_Any * >( pCallStack[0] ),
363 &pInterface, pTD, cpp_acquire );
364 pInterface->release();
365 TYPELIB_DANGER_RELEASE( pTD );
366 *(void **)pRegisterReturn = pCallStack[0];
367 eRet = typelib_TypeClass_ANY;
368 break;
369 }
370 TYPELIB_DANGER_RELEASE( pTD );
371 }
372 } // else perform queryInterface()
373 default:
374 eRet = cpp2uno_call(
375 pCppI, aMemberDescr.get(),
376 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef,
377 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams,
378 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams,
379 pCallStack, pRegisterReturn );
380 }
381 break;
382 }
383 default:
384 {
385 throw RuntimeException(
386 OUString::createFromAscii("no member description found!"),
387 (XInterface *)pCppI );
388 // is here for dummy
389 eRet = typelib_TypeClass_VOID;
390 }
391 }
392
393 return eRet;
394 }
395 }
396
397 //=======================================================================
398 /**
399 * is called on incoming vtable calls
400 * (called by asm snippets)
401 */
402
cpp_vtable_call(long * pFunctionAndOffset,void ** pCallStack)403 extern "C" sal_Int64 cpp_vtable_call( long *pFunctionAndOffset,
404 void **pCallStack )
405 {
406 sal_Int64 nRegReturn;
407 typelib_TypeClass aType = cpp_mediate( pFunctionAndOffset[0], pFunctionAndOffset[1], pCallStack,
408 &nRegReturn );
409
410 switch( aType )
411 {
412 case typelib_TypeClass_BOOLEAN:
413 case typelib_TypeClass_BYTE:
414 nRegReturn = (unsigned long)(*(unsigned char *)&nRegReturn);
415 break;
416 case typelib_TypeClass_CHAR:
417 case typelib_TypeClass_UNSIGNED_SHORT:
418 case typelib_TypeClass_SHORT:
419 nRegReturn = (unsigned long)(*(unsigned short *)&nRegReturn);
420 break;
421 case typelib_TypeClass_ENUM:
422 case typelib_TypeClass_UNSIGNED_LONG:
423 case typelib_TypeClass_LONG:
424 nRegReturn = (unsigned long)(*(unsigned int *)&nRegReturn);
425 break;
426 case typelib_TypeClass_VOID:
427 default:
428 break;
429 }
430
431 return nRegReturn;
432 }
433
434 extern "C" void privateSnippetExecutor(void);
435
436 namespace
437 {
438 const int codeSnippetSize = 20;
439
codeSnippet(unsigned char * code,sal_Int32 functionIndex,sal_Int32 vtableOffset,bool bHasHiddenParam)440 unsigned char *codeSnippet(unsigned char* code, sal_Int32 functionIndex,
441 sal_Int32 vtableOffset, bool bHasHiddenParam)
442 {
443 if (bHasHiddenParam)
444 functionIndex |= 0x80000000;
445
446 unsigned long * p = (unsigned long *)code;
447
448 *p++ = 0xE1A0C00F;
449 *p++ = 0xE59FF004;
450 *p++ = (unsigned long)functionIndex;
451 *p++ = (unsigned long)vtableOffset;
452 *p++ = (unsigned long)privateSnippetExecutor;
453
454 return code + codeSnippetSize;
455 }
456 }
457
458 struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; };
459
460 bridges::cpp_uno::shared::VtableFactory::Slot *
mapBlockToVtable(void * block)461 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
462 {
463 return static_cast< Slot * >(block) + 2;
464 }
465
getBlockSize(sal_Int32 slotCount)466 sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize(
467 sal_Int32 slotCount)
468 {
469 return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
470 }
471
472 bridges::cpp_uno::shared::VtableFactory::Slot *
initializeBlock(void * block,sal_Int32 slotCount)473 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
474 void * block, sal_Int32 slotCount)
475 {
476 Slot * slots = mapBlockToVtable(block);
477 slots[-2].fn = 0;
478 slots[-1].fn = 0;
479 return slots + slotCount;
480 }
481
addLocalFunctions(Slot ** slots,unsigned char * code,sal_PtrDiff writetoexecdiff,typelib_InterfaceTypeDescription const * type,sal_Int32 functionOffset,sal_Int32 functionCount,sal_Int32 vtableOffset)482 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
483 Slot ** slots, unsigned char * code, sal_PtrDiff writetoexecdiff,
484 typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
485 sal_Int32 functionCount, sal_Int32 vtableOffset)
486 {
487 (*slots) -= functionCount;
488 Slot * s = *slots;
489 for (sal_Int32 i = 0; i < type->nMembers; ++i)
490 {
491 typelib_TypeDescription * member = 0;
492 TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
493 OSL_ASSERT(member != 0);
494 switch (member->eTypeClass)
495 {
496 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
497 {
498 typelib_InterfaceAttributeTypeDescription *pAttrTD =
499 reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( member );
500
501 // Getter:
502 (s++)->fn = code + writetoexecdiff;
503 code = codeSnippet(
504 code, functionOffset++, vtableOffset,
505 arm::return_in_hidden_param( pAttrTD->pAttributeTypeRef ));
506
507 // Setter:
508 if (!pAttrTD->bReadOnly)
509 {
510 (s++)->fn = code + writetoexecdiff;
511 code = codeSnippet(
512 code, functionOffset++, vtableOffset, false);
513 }
514 break;
515 }
516 case typelib_TypeClass_INTERFACE_METHOD:
517 {
518 (s++)->fn = code + writetoexecdiff;
519
520 typelib_InterfaceMethodTypeDescription *pMethodTD =
521 reinterpret_cast<
522 typelib_InterfaceMethodTypeDescription * >(member);
523
524 code = codeSnippet(code, functionOffset++, vtableOffset,
525 arm::return_in_hidden_param(pMethodTD->pReturnTypeRef));
526 break;
527 }
528 default:
529 OSL_ASSERT(false);
530 break;
531 }
532 TYPELIB_DANGER_RELEASE(member);
533 }
534 return code;
535 }
536
flushCode(unsigned char const * beg,unsigned char const * end)537 void bridges::cpp_uno::shared::VtableFactory::flushCode(
538 unsigned char const *beg, unsigned char const *end)
539 {
540 static void (*clear_cache)(unsigned char const*, unsigned char const*)
541 = (void (*)(unsigned char const*, unsigned char const*))
542 dlsym(RTLD_DEFAULT, "__clear_cache");
543 (*clear_cache)(beg, end);
544 }
545
546 /* vi:set tabstop=4 shiftwidth=4 expandtab: */
547