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