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 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_bridges.hxx"
26
27 #include <typeinfo>
28 #include <exception>
29 #include <cstddef>
30 #include <cxxabi.h>
31 #include <stdlib.h>
32
33 #include <com/sun/star/uno/genfunc.hxx>
34 #include "com/sun/star/uno/RuntimeException.hpp"
35 #include <uno/data.h>
36
37 #include "bridges/cpp_uno/shared/bridge.hxx"
38 #include "bridges/cpp_uno/shared/types.hxx"
39 #include "bridges/cpp_uno/shared/unointerfaceproxy.hxx"
40 #include "bridges/cpp_uno/shared/vtables.hxx"
41
42 #include "share.hxx"
43
44 using namespace ::rtl;
45 using namespace ::com::sun::star::uno;
46 #ifdef __GLIBCXX__
47 using CPPU_CURRENT_NAMESPACE::__cxa_get_globals;
48 #else
49 using __cxxabiv1::__cxa_get_globals;
50 #endif
51
52 namespace
53 {
54
55 //==================================================================================================
56 // The call instruction within the asm section of callVirtualMethod may throw
57 // exceptions. So that the compiler handles this correctly, it is important
58 // that (a) callVirtualMethod might call dummy_can_throw_anything (although this
59 // never happens at runtime), which in turn can throw exceptions, and (b)
60 // callVirtualMethod is not inlined at its call site (so that any exceptions are
61 // caught which are thrown from the instruction calling callVirtualMethod):
62 void callVirtualMethod(
63 void * pAdjustedThisPtr,
64 sal_Int32 nVtableIndex,
65 void * pRegisterReturn,
66 typelib_TypeClass eReturnType,
67 sal_Int32 * pStackLongs,
68 sal_Int32 nStackLongs ) __attribute__((noinline));
69
callVirtualMethod(void * pAdjustedThisPtr,sal_Int32 nVtableIndex,void * pRegisterReturn,typelib_TypeClass eReturnType,sal_Int32 * pStackLongs,sal_Int32 nStackLongs)70 void callVirtualMethod(
71 void * pAdjustedThisPtr,
72 sal_Int32 nVtableIndex,
73 void * pRegisterReturn,
74 typelib_TypeClass eReturnType,
75 sal_Int32 * pStackLongs,
76 sal_Int32 nStackLongs )
77 {
78 // parameter list is mixed list of * and values
79 // reference parameters are pointers
80
81 OSL_ENSURE( pStackLongs && pAdjustedThisPtr, "### null ptr!" );
82 OSL_ENSURE( (sizeof(void *) == 4) && (sizeof(sal_Int32) == 4), "### unexpected size of int!" );
83 OSL_ENSURE( nStackLongs && pStackLongs, "### no stack in callVirtualMethod !" );
84
85 // never called
86 if (! pAdjustedThisPtr) CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything("xxx"); // address something
87
88 volatile long edx = 0, eax = 0; // for register returns
89 void * stackptr;
90 asm volatile (
91 "mov %%esp, %6\n\t"
92 // preserve potential 128bit stack alignment
93 "and $0xfffffff0, %%esp\n\t"
94 "mov %0, %%eax\n\t"
95 "lea -4(,%%eax,4), %%eax\n\t"
96 "and $0xf, %%eax\n\t"
97 "sub $0xc, %%eax\n\t"
98 "add %%eax, %%esp\n\t"
99 // copy values
100 "mov %0, %%eax\n\t"
101 "mov %%eax, %%edx\n\t"
102 "dec %%edx\n\t"
103 "shl $2, %%edx\n\t"
104 "add %1, %%edx\n"
105 "Lcopy:\n\t"
106 "pushl 0(%%edx)\n\t"
107 "sub $4, %%edx\n\t"
108 "dec %%eax\n\t"
109 "jne Lcopy\n\t"
110 // do the actual call
111 "mov %2, %%edx\n\t"
112 "mov 0(%%edx), %%edx\n\t"
113 "mov %3, %%eax\n\t"
114 "shl $2, %%eax\n\t"
115 "add %%eax, %%edx\n\t"
116 "mov 0(%%edx), %%edx\n\t"
117 "call *%%edx\n\t"
118 // save return registers
119 "mov %%eax, %4\n\t"
120 "mov %%edx, %5\n\t"
121 // cleanup stack
122 "mov %6, %%esp\n\t"
123 :
124 : "m"(nStackLongs), "m"(pStackLongs), "m"(pAdjustedThisPtr),
125 "m"(nVtableIndex), "m"(eax), "m"(edx), "m"(stackptr)
126 : "eax", "edx" );
127 switch( eReturnType )
128 {
129 case typelib_TypeClass_HYPER:
130 case typelib_TypeClass_UNSIGNED_HYPER:
131 ((long*)pRegisterReturn)[1] = edx;
132 case typelib_TypeClass_LONG:
133 case typelib_TypeClass_UNSIGNED_LONG:
134 case typelib_TypeClass_CHAR:
135 case typelib_TypeClass_ENUM:
136 ((long*)pRegisterReturn)[0] = eax;
137 break;
138 case typelib_TypeClass_SHORT:
139 case typelib_TypeClass_UNSIGNED_SHORT:
140 *(unsigned short*)pRegisterReturn = eax;
141 break;
142 case typelib_TypeClass_BOOLEAN:
143 case typelib_TypeClass_BYTE:
144 *(unsigned char*)pRegisterReturn = eax;
145 break;
146 case typelib_TypeClass_FLOAT:
147 asm ( "fstps %0" : : "m"(*(char *)pRegisterReturn) );
148 break;
149 case typelib_TypeClass_DOUBLE:
150 asm ( "fstpl %0\n\t" : : "m"(*(char *)pRegisterReturn) );
151 break;
152 default:
153 break;
154 }
155 }
156
157 //==================================================================================================
cpp_call(bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,bridges::cpp_uno::shared::VtableSlot aVtableSlot,typelib_TypeDescriptionReference * pReturnTypeRef,sal_Int32 nParams,typelib_MethodParameter * pParams,void * pUnoReturn,void * pUnoArgs[],uno_Any ** ppUnoExc)158 static void cpp_call(
159 bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
160 bridges::cpp_uno::shared::VtableSlot aVtableSlot,
161 typelib_TypeDescriptionReference * pReturnTypeRef,
162 sal_Int32 nParams, typelib_MethodParameter * pParams,
163 void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
164 {
165 // max space for: [complex ret ptr], values|ptr ...
166 char * pCppStack =
167 (char *)alloca( sizeof(sal_Int32) + ((nParams+2) * sizeof(sal_Int64)) );
168 char * pCppStackStart = pCppStack;
169
170 // return
171 typelib_TypeDescription * pReturnTypeDescr = 0;
172 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
173 OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" );
174
175 void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
176
177 if (pReturnTypeDescr)
178 {
179 if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr ))
180 {
181 pCppReturn = pUnoReturn; // direct way for simple types
182 }
183 else
184 {
185 // complex return via ptr
186 pCppReturn = *(void **)pCppStack
187 = (bridges::cpp_uno::shared::relatesToInterfaceType(
188 pReturnTypeDescr )
189 ? alloca( pReturnTypeDescr->nSize )
190 : pUnoReturn); // direct way
191 pCppStack += sizeof(void *);
192 }
193 }
194 // push this
195 void * pAdjustedThisPtr = reinterpret_cast< void ** >(pThis->getCppI())
196 + aVtableSlot.offset;
197 *(void**)pCppStack = pAdjustedThisPtr;
198 pCppStack += sizeof( void* );
199
200 // stack space
201 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" );
202 // args
203 void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams );
204 // indizes of values this have to be converted (interface conversion cpp<=>uno)
205 sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams);
206 // type descriptions for reconversions
207 typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
208
209 sal_Int32 nTempIndizes = 0;
210
211 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
212 {
213 const typelib_MethodParameter & rParam = pParams[nPos];
214 typelib_TypeDescription * pParamTypeDescr = 0;
215 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
216
217 if (!rParam.bOut
218 && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
219 {
220 uno_copyAndConvertData( pCppArgs[nPos] = pCppStack, pUnoArgs[nPos], pParamTypeDescr,
221 pThis->getBridge()->getUno2Cpp() );
222
223 switch (pParamTypeDescr->eTypeClass)
224 {
225 case typelib_TypeClass_HYPER:
226 case typelib_TypeClass_UNSIGNED_HYPER:
227 case typelib_TypeClass_DOUBLE:
228 pCppStack += sizeof(sal_Int32); // extra long
229 break;
230 default:
231 break;
232 }
233 // no longer needed
234 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
235 }
236 else // ptr to complex value | ref
237 {
238 if (! rParam.bIn) // is pure out
239 {
240 // cpp out is constructed mem, uno out is not!
241 uno_constructData(
242 *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
243 pParamTypeDescr );
244 pTempIndizes[nTempIndizes] = nPos; // default constructed for cpp call
245 // will be released at reconversion
246 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
247 }
248 // is in/inout
249 else if (bridges::cpp_uno::shared::relatesToInterfaceType(
250 pParamTypeDescr ))
251 {
252 uno_copyAndConvertData(
253 *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
254 pUnoArgs[nPos], pParamTypeDescr,
255 pThis->getBridge()->getUno2Cpp() );
256
257 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
258 // will be released at reconversion
259 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
260 }
261 else // direct way
262 {
263 *(void **)pCppStack = pCppArgs[nPos] = pUnoArgs[nPos];
264 // no longer needed
265 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
266 }
267 }
268 pCppStack += sizeof(sal_Int32); // standard parameter length
269 }
270
271 try
272 {
273 OSL_ENSURE( !( (pCppStack - pCppStackStart ) & 3), "UNALIGNED STACK !!! (Please DO panic)" );
274 callVirtualMethod(
275 pAdjustedThisPtr, aVtableSlot.index,
276 pCppReturn, pReturnTypeDescr->eTypeClass,
277 (sal_Int32 *)pCppStackStart, (pCppStack - pCppStackStart) / sizeof(sal_Int32) );
278 // NO exception occured...
279 *ppUnoExc = 0;
280
281 // reconvert temporary params
282 for ( ; nTempIndizes--; )
283 {
284 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
285 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
286
287 if (pParams[nIndex].bIn)
288 {
289 if (pParams[nIndex].bOut) // inout
290 {
291 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
292 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
293 pThis->getBridge()->getCpp2Uno() );
294 }
295 }
296 else // pure out
297 {
298 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
299 pThis->getBridge()->getCpp2Uno() );
300 }
301 // destroy temp cpp param => cpp: every param was constructed
302 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
303
304 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
305 }
306 // return value
307 if (pCppReturn && pUnoReturn != pCppReturn)
308 {
309 uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
310 pThis->getBridge()->getCpp2Uno() );
311 uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
312 }
313 }
314 catch (...)
315 {
316 // fill uno exception
317 CPPU_CURRENT_NAMESPACE::fillUnoException( __cxa_get_globals()->caughtExceptions, *ppUnoExc, pThis->getBridge()->getCpp2Uno() );
318
319 // temporary params
320 for ( ; nTempIndizes--; )
321 {
322 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
323 // destroy temp cpp param => cpp: every param was constructed
324 uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], cpp_release );
325 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
326 }
327 // return type
328 if (pReturnTypeDescr)
329 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
330 }
331 }
332
333 }
334
335 namespace bridges { namespace cpp_uno { namespace shared {
336
unoInterfaceProxyDispatch(uno_Interface * pUnoI,const typelib_TypeDescription * pMemberDescr,void * pReturn,void * pArgs[],uno_Any ** ppException)337 void unoInterfaceProxyDispatch(
338 uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
339 void * pReturn, void * pArgs[], uno_Any ** ppException )
340 {
341 // is my surrogate
342 bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
343 = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
344
345 switch (pMemberDescr->eTypeClass)
346 {
347 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
348 {
349 VtableSlot aVtableSlot(
350 getVtableSlot(
351 reinterpret_cast<
352 typelib_InterfaceAttributeTypeDescription const * >(
353 pMemberDescr)));
354 if (pReturn)
355 {
356 // dependent dispatch
357 cpp_call(
358 pThis, aVtableSlot,
359 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
360 0, 0, // no params
361 pReturn, pArgs, ppException );
362 }
363 else
364 {
365 // is SET
366 typelib_MethodParameter aParam;
367 aParam.pTypeRef =
368 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
369 aParam.bIn = sal_True;
370 aParam.bOut = sal_False;
371
372 typelib_TypeDescriptionReference * pReturnTypeRef = 0;
373 OUString aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") );
374 typelib_typedescriptionreference_new(
375 &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
376
377 // dependent dispatch
378 aVtableSlot.index += 1; // get, then set method
379 cpp_call(
380 pThis, aVtableSlot,
381 pReturnTypeRef,
382 1, &aParam,
383 pReturn, pArgs, ppException );
384
385 typelib_typedescriptionreference_release( pReturnTypeRef );
386 }
387
388 break;
389 }
390 case typelib_TypeClass_INTERFACE_METHOD:
391 {
392 VtableSlot aVtableSlot(
393 getVtableSlot(
394 reinterpret_cast<
395 typelib_InterfaceMethodTypeDescription const * >(
396 pMemberDescr)));
397 switch (aVtableSlot.index)
398 {
399 // standard calls
400 case 1: // acquire uno interface
401 (*pUnoI->acquire)( pUnoI );
402 *ppException = 0;
403 break;
404 case 2: // release uno interface
405 (*pUnoI->release)( pUnoI );
406 *ppException = 0;
407 break;
408 case 0: // queryInterface() opt
409 {
410 typelib_TypeDescription * pTD = 0;
411 TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() );
412 if (pTD)
413 {
414 uno_Interface * pInterface = 0;
415 (*pThis->pBridge->getUnoEnv()->getRegisteredInterface)(
416 pThis->pBridge->getUnoEnv(),
417 (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
418
419 if (pInterface)
420 {
421 ::uno_any_construct(
422 reinterpret_cast< uno_Any * >( pReturn ),
423 &pInterface, pTD, 0 );
424 (*pInterface->release)( pInterface );
425 TYPELIB_DANGER_RELEASE( pTD );
426 *ppException = 0;
427 break;
428 }
429 TYPELIB_DANGER_RELEASE( pTD );
430 }
431 } // else perform queryInterface()
432 default:
433 // dependent dispatch
434 cpp_call(
435 pThis, aVtableSlot,
436 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef,
437 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams,
438 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams,
439 pReturn, pArgs, ppException );
440 }
441 break;
442 }
443 default:
444 {
445 ::com::sun::star::uno::RuntimeException aExc(
446 OUString( RTL_CONSTASCII_USTRINGPARAM("illegal member type description!") ),
447 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
448
449 Type const & rExcType = ::getCppuType( &aExc );
450 // binary identical null reference
451 ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
452 }
453 }
454 }
455
456 } } }
457