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