Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #if defined (FREEBSD) || defined(NETBSD) || defined(OPENBSD) || defined(DRAGONFLY)
22 : #include <stdlib.h>
23 : #else
24 : #include <alloca.h>
25 : #endif
26 :
27 : #include <com/sun/star/uno/genfunc.hxx>
28 : #include "com/sun/star/uno/RuntimeException.hpp"
29 : #include <uno/data.h>
30 :
31 : #include "bridges/cpp_uno/shared/bridge.hxx"
32 : #include "bridges/cpp_uno/shared/types.hxx"
33 : #include "bridges/cpp_uno/shared/unointerfaceproxy.hxx"
34 : #include "bridges/cpp_uno/shared/vtables.hxx"
35 :
36 : #include "callvirtualmethod.hxx"
37 : #include "share.hxx"
38 :
39 : using namespace ::rtl;
40 : using namespace ::com::sun::star::uno;
41 :
42 : namespace
43 : {
44 :
45 436 : static void cpp_call(
46 : bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
47 : bridges::cpp_uno::shared::VtableSlot aVtableSlot,
48 : typelib_TypeDescriptionReference * pReturnTypeRef,
49 : sal_Int32 nParams, typelib_MethodParameter * pParams,
50 : void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
51 : {
52 : // max space for: [complex ret ptr], values|ptr ...
53 : char * pCppStack =
54 436 : (char *)alloca( sizeof(sal_Int32) + ((nParams+2) * sizeof(sal_Int64)) );
55 436 : char * pCppStackStart = pCppStack;
56 :
57 : // return
58 436 : typelib_TypeDescription * pReturnTypeDescr = 0;
59 436 : TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
60 : OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" );
61 :
62 436 : void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
63 436 : bool bSimpleReturn = true;
64 :
65 436 : if (pReturnTypeDescr)
66 : {
67 436 : bSimpleReturn = x86::isSimpleReturnType(pReturnTypeDescr);
68 436 : if (bSimpleReturn)
69 : {
70 308 : pCppReturn = pUnoReturn; // direct way for simple types
71 : }
72 : else
73 : {
74 : // complex return via ptr
75 : pCppReturn = *(void **)pCppStack
76 : = (bridges::cpp_uno::shared::relatesToInterfaceType(
77 128 : pReturnTypeDescr )
78 53 : ? alloca( pReturnTypeDescr->nSize )
79 181 : : pUnoReturn); // direct way
80 128 : pCppStack += sizeof(void *);
81 : }
82 : }
83 : // push this
84 436 : void * pAdjustedThisPtr = reinterpret_cast< void ** >(pThis->getCppI())
85 436 : + aVtableSlot.offset;
86 436 : *(void**)pCppStack = pAdjustedThisPtr;
87 436 : pCppStack += sizeof( void* );
88 :
89 : // stack space
90 : OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" );
91 : // args
92 436 : void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams );
93 : // indizes of values this have to be converted (interface conversion cpp<=>uno)
94 436 : sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams);
95 : // type descriptions for reconversions
96 436 : typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
97 :
98 436 : sal_Int32 nTempIndizes = 0;
99 :
100 947 : for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
101 : {
102 511 : const typelib_MethodParameter & rParam = pParams[nPos];
103 511 : typelib_TypeDescription * pParamTypeDescr = 0;
104 511 : TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
105 :
106 935 : if (!rParam.bOut
107 424 : && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
108 : {
109 759 : uno_copyAndConvertData( pCppArgs[nPos] = pCppStack, pUnoArgs[nPos], pParamTypeDescr,
110 1012 : pThis->getBridge()->getUno2Cpp() );
111 :
112 253 : switch (pParamTypeDescr->eTypeClass)
113 : {
114 : case typelib_TypeClass_HYPER:
115 : case typelib_TypeClass_UNSIGNED_HYPER:
116 : case typelib_TypeClass_DOUBLE:
117 23 : pCppStack += sizeof(sal_Int32); // extra long
118 23 : break;
119 : default:
120 230 : break;
121 : }
122 : // no longer needed
123 253 : TYPELIB_DANGER_RELEASE( pParamTypeDescr );
124 : }
125 : else // ptr to complex value | ref
126 : {
127 258 : if (! rParam.bIn) // is pure out
128 : {
129 : // cpp out is constructed mem, uno out is not!
130 : uno_constructData(
131 104 : *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
132 156 : pParamTypeDescr );
133 52 : pTempIndizes[nTempIndizes] = nPos; // default constructed for cpp call
134 : // will be released at reconversion
135 52 : ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
136 : }
137 : // is in/inout
138 206 : else if (bridges::cpp_uno::shared::relatesToInterfaceType(
139 206 : pParamTypeDescr ))
140 : {
141 : uno_copyAndConvertData(
142 212 : *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
143 106 : pUnoArgs[nPos], pParamTypeDescr,
144 424 : pThis->getBridge()->getUno2Cpp() );
145 :
146 106 : pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
147 : // will be released at reconversion
148 106 : ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
149 : }
150 : else // direct way
151 : {
152 100 : *(void **)pCppStack = pCppArgs[nPos] = pUnoArgs[nPos];
153 : // no longer needed
154 100 : TYPELIB_DANGER_RELEASE( pParamTypeDescr );
155 : }
156 : }
157 511 : pCppStack += sizeof(sal_Int32); // standard parameter length
158 : }
159 :
160 : try
161 : {
162 : OSL_ENSURE( !( (pCppStack - pCppStackStart ) & 3), "UNALIGNED STACK !!! (Please DO panic)" );
163 : CPPU_CURRENT_NAMESPACE::callVirtualMethod(
164 : pAdjustedThisPtr, aVtableSlot.index,
165 : pCppReturn, pReturnTypeDescr, bSimpleReturn,
166 436 : (sal_Int32 *)pCppStackStart, (pCppStack - pCppStackStart) / sizeof(sal_Int32) );
167 : // NO exception occurred...
168 353 : *ppUnoExc = 0;
169 :
170 : // reconvert temporary params
171 862 : for ( ; nTempIndizes--; )
172 : {
173 156 : sal_Int32 nIndex = pTempIndizes[nTempIndizes];
174 156 : typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
175 :
176 156 : if (pParams[nIndex].bIn)
177 : {
178 104 : if (pParams[nIndex].bOut) // inout
179 : {
180 6 : uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
181 12 : uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
182 18 : pThis->getBridge()->getCpp2Uno() );
183 : }
184 : }
185 : else // pure out
186 : {
187 104 : uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
188 156 : pThis->getBridge()->getCpp2Uno() );
189 : }
190 : // destroy temp cpp param => cpp: every param was constructed
191 156 : uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
192 :
193 156 : TYPELIB_DANGER_RELEASE( pParamTypeDescr );
194 : }
195 : // return value
196 353 : if (pCppReturn && pUnoReturn != pCppReturn)
197 : {
198 : uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
199 52 : pThis->getBridge()->getCpp2Uno() );
200 52 : uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
201 : }
202 : }
203 83 : catch (...)
204 : {
205 : // fill uno exception
206 83 : fillUnoException( __cxa_get_globals()->caughtExceptions, *ppUnoExc, pThis->getBridge()->getCpp2Uno() );
207 :
208 : // temporary params
209 168 : for ( ; nTempIndizes--; )
210 : {
211 2 : sal_Int32 nIndex = pTempIndizes[nTempIndizes];
212 : // destroy temp cpp param => cpp: every param was constructed
213 2 : uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], cpp_release );
214 2 : TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
215 : }
216 : // return type
217 83 : if (pReturnTypeDescr)
218 83 : TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
219 : }
220 436 : }
221 :
222 : }
223 :
224 : namespace x86
225 : {
226 2423 : bool isSimpleReturnType(typelib_TypeDescription * pTD, bool recursive)
227 : {
228 2423 : if (bridges::cpp_uno::shared::isSimpleType( pTD ))
229 2173 : return true;
230 : #if defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) || \
231 : defined(MACOSX) || defined(DRAGONFLY)
232 : // Only structs of exactly 1, 2, 4, or 8 bytes are returned through
233 : // registers, see <http://developer.apple.com/documentation/DeveloperTools/
234 : // Conceptual/LowLevelABI/Articles/IA32.html>:
235 : if (pTD->eTypeClass == typelib_TypeClass_STRUCT &&
236 : (recursive || pTD->nSize <= 2 || pTD->nSize == 4 || pTD->nSize == 8))
237 : {
238 : typelib_CompoundTypeDescription *const pCompTD =
239 : (typelib_CompoundTypeDescription *) pTD;
240 : for ( sal_Int32 pos = pCompTD->nMembers; pos--; ) {
241 : typelib_TypeDescription * pMemberTD = 0;
242 : TYPELIB_DANGER_GET( &pMemberTD, pCompTD->ppTypeRefs[pos] );
243 : bool const b = isSimpleReturnType(pMemberTD, true);
244 : TYPELIB_DANGER_RELEASE( pMemberTD );
245 : if (! b)
246 : return false;
247 : }
248 : return true;
249 : }
250 : #else
251 : (void)recursive;
252 : #endif
253 250 : return false;
254 : }
255 : }
256 :
257 : namespace bridges { namespace cpp_uno { namespace shared {
258 :
259 436 : void unoInterfaceProxyDispatch(
260 : uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
261 : void * pReturn, void * pArgs[], uno_Any ** ppException )
262 : {
263 : // is my surrogate
264 : bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
265 436 : = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
266 :
267 436 : switch (pMemberDescr->eTypeClass)
268 : {
269 : case typelib_TypeClass_INTERFACE_ATTRIBUTE:
270 : {
271 : VtableSlot aVtableSlot(
272 : getVtableSlot(
273 : reinterpret_cast<
274 : typelib_InterfaceAttributeTypeDescription const * >(
275 93 : pMemberDescr)));
276 93 : if (pReturn)
277 : {
278 : // dependent dispatch
279 : cpp_call(
280 : pThis, aVtableSlot,
281 : ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
282 : 0, 0, // no params
283 64 : pReturn, pArgs, ppException );
284 : }
285 : else
286 : {
287 : // is SET
288 : typelib_MethodParameter aParam;
289 : aParam.pTypeRef =
290 29 : ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
291 29 : aParam.bIn = sal_True;
292 29 : aParam.bOut = sal_False;
293 :
294 29 : typelib_TypeDescriptionReference * pReturnTypeRef = 0;
295 29 : OUString aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") );
296 : typelib_typedescriptionreference_new(
297 29 : &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
298 :
299 : // dependent dispatch
300 29 : aVtableSlot.index += 1; // get, then set method
301 : cpp_call(
302 : pThis, aVtableSlot,
303 : pReturnTypeRef,
304 : 1, &aParam,
305 29 : pReturn, pArgs, ppException );
306 :
307 29 : typelib_typedescriptionreference_release( pReturnTypeRef );
308 : }
309 :
310 : break;
311 : }
312 : case typelib_TypeClass_INTERFACE_METHOD:
313 : {
314 : VtableSlot aVtableSlot(
315 : getVtableSlot(
316 : reinterpret_cast<
317 : typelib_InterfaceMethodTypeDescription const * >(
318 343 : pMemberDescr)));
319 343 : switch (aVtableSlot.index)
320 : {
321 : // standard calls
322 : case 1: // acquire uno interface
323 0 : (*pUnoI->acquire)( pUnoI );
324 0 : *ppException = 0;
325 0 : break;
326 : case 2: // release uno interface
327 0 : (*pUnoI->release)( pUnoI );
328 0 : *ppException = 0;
329 0 : break;
330 : case 0: // queryInterface() opt
331 : {
332 4 : typelib_TypeDescription * pTD = 0;
333 4 : TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() );
334 4 : if (pTD)
335 : {
336 4 : uno_Interface * pInterface = 0;
337 4 : (*pThis->pBridge->getUnoEnv()->getRegisteredInterface)(
338 : pThis->pBridge->getUnoEnv(),
339 4 : (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
340 :
341 4 : if (pInterface)
342 : {
343 : ::uno_any_construct(
344 : reinterpret_cast< uno_Any * >( pReturn ),
345 0 : &pInterface, pTD, 0 );
346 0 : (*pInterface->release)( pInterface );
347 0 : TYPELIB_DANGER_RELEASE( pTD );
348 0 : *ppException = 0;
349 : break;
350 : }
351 4 : TYPELIB_DANGER_RELEASE( pTD );
352 : }
353 : } // else perform queryInterface()
354 : default:
355 : // dependent dispatch
356 : cpp_call(
357 : pThis, aVtableSlot,
358 : ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef,
359 : ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams,
360 : ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams,
361 343 : pReturn, pArgs, ppException );
362 : }
363 : break;
364 : }
365 : default:
366 : {
367 : ::com::sun::star::uno::RuntimeException aExc(
368 : OUString( RTL_CONSTASCII_USTRINGPARAM("illegal member type description!") ),
369 0 : ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
370 :
371 0 : Type const & rExcType = ::getCppuType( &aExc );
372 : // binary identical null reference
373 0 : ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
374 : }
375 : }
376 436 : }
377 :
378 : } } }
379 :
380 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|