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