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 : #if defined (FREEBSD) || defined(NETBSD) || defined(OPENBSD) || defined(DRAGONFLY)
21 : #include <stdlib.h>
22 : #else
23 : #include <alloca.h>
24 : #endif
25 : #include <exception>
26 : #include <typeinfo>
27 :
28 : #include "rtl/alloc.h"
29 : #include "rtl/ustrbuf.hxx"
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 "abi.hxx"
41 : #include "callvirtualmethod.hxx"
42 : #include "share.hxx"
43 :
44 : using namespace ::com::sun::star::uno;
45 :
46 : // Macros for easier insertion of values to registers or stack
47 : // pSV - pointer to the source
48 : // nr - order of the value [will be increased if stored to register]
49 : // pFPR, pGPR - pointer to the registers
50 : // pDS - pointer to the stack [will be increased if stored here]
51 :
52 : // The value in %xmm register is already prepared to be retrieved as a float,
53 : // thus we treat float and double the same
54 : #define INSERT_FLOAT_DOUBLE( pSV, nr, pFPR, pDS ) \
55 : if ( nr < x86_64::MAX_SSE_REGS ) \
56 : pFPR[nr++] = *reinterpret_cast<double *>( pSV ); \
57 : else \
58 : *pDS++ = *reinterpret_cast<sal_uInt64 *>( pSV ); // verbatim!
59 :
60 : #define INSERT_INT64( pSV, nr, pGPR, pDS ) \
61 : if ( nr < x86_64::MAX_GPR_REGS ) \
62 : pGPR[nr++] = *reinterpret_cast<sal_uInt64 *>( pSV ); \
63 : else \
64 : *pDS++ = *reinterpret_cast<sal_uInt64 *>( pSV );
65 :
66 : #define INSERT_INT32( pSV, nr, pGPR, pDS ) \
67 : if ( nr < x86_64::MAX_GPR_REGS ) \
68 : pGPR[nr++] = *reinterpret_cast<sal_uInt32 *>( pSV ); \
69 : else \
70 : *pDS++ = *reinterpret_cast<sal_uInt32 *>( pSV );
71 :
72 : #define INSERT_INT16( pSV, nr, pGPR, pDS ) \
73 : if ( nr < x86_64::MAX_GPR_REGS ) \
74 : pGPR[nr++] = *reinterpret_cast<sal_uInt16 *>( pSV ); \
75 : else \
76 : *pDS++ = *reinterpret_cast<sal_uInt16 *>( pSV );
77 :
78 : #define INSERT_INT8( pSV, nr, pGPR, pDS ) \
79 : if ( nr < x86_64::MAX_GPR_REGS ) \
80 : pGPR[nr++] = *reinterpret_cast<sal_uInt8 *>( pSV ); \
81 : else \
82 : *pDS++ = *reinterpret_cast<sal_uInt8 *>( pSV );
83 :
84 :
85 : namespace {
86 :
87 0 : void appendCString(OUStringBuffer & buffer, char const * text) {
88 0 : if (text != 0) {
89 : buffer.append(
90 0 : OStringToOUString(OString(text), RTL_TEXTENCODING_ISO_8859_1));
91 : // use 8859-1 to avoid conversion failure
92 : }
93 0 : }
94 :
95 : }
96 :
97 419738 : static void cpp_call(
98 : bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
99 : bridges::cpp_uno::shared::VtableSlot aVtableSlot,
100 : typelib_TypeDescriptionReference * pReturnTypeRef,
101 : sal_Int32 nParams, typelib_MethodParameter * pParams,
102 : void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
103 : {
104 : // Maxium space for [complex ret ptr], values | ptr ...
105 : // (but will be used less - some of the values will be in pGPR and pFPR)
106 419738 : sal_uInt64 *pStack = (sal_uInt64 *)__builtin_alloca( (nParams + 3) * sizeof(sal_uInt64) );
107 419738 : sal_uInt64 *pStackStart = pStack;
108 :
109 : sal_uInt64 pGPR[x86_64::MAX_GPR_REGS];
110 419738 : sal_uInt32 nGPR = 0;
111 :
112 : double pFPR[x86_64::MAX_SSE_REGS];
113 419738 : sal_uInt32 nFPR = 0;
114 :
115 : // Return
116 419738 : typelib_TypeDescription * pReturnTypeDescr = 0;
117 419738 : TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
118 : OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" );
119 :
120 419738 : void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion (see below)
121 :
122 419738 : bool bSimpleReturn = true;
123 419738 : if ( pReturnTypeDescr )
124 : {
125 419738 : if ( x86_64::return_in_hidden_param( pReturnTypeRef ) )
126 255952 : bSimpleReturn = false;
127 :
128 419738 : if ( bSimpleReturn )
129 163786 : pCppReturn = pUnoReturn; // direct way for simple types
130 : else
131 : {
132 : // complex return via ptr
133 255952 : pCppReturn = bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )?
134 255952 : __builtin_alloca( pReturnTypeDescr->nSize ) : pUnoReturn;
135 255952 : INSERT_INT64( &pCppReturn, nGPR, pGPR, pStack );
136 : }
137 : }
138 :
139 : // Push "this" pointer
140 419738 : void * pAdjustedThisPtr = reinterpret_cast< void ** >( pThis->getCppI() ) + aVtableSlot.offset;
141 419738 : INSERT_INT64( &pAdjustedThisPtr, nGPR, pGPR, pStack );
142 :
143 : // Args
144 419738 : void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams );
145 : // Indices of values this have to be converted (interface conversion cpp<=>uno)
146 419738 : sal_Int32 * pTempIndices = (sal_Int32 *)(pCppArgs + nParams);
147 : // Type descriptions for reconversions
148 419738 : typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
149 :
150 419738 : sal_Int32 nTempIndices = 0;
151 :
152 755246 : for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
153 : {
154 335508 : const typelib_MethodParameter & rParam = pParams[nPos];
155 335508 : typelib_TypeDescription * pParamTypeDescr = 0;
156 335508 : TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
157 :
158 335508 : if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
159 : {
160 233922 : uno_copyAndConvertData( pCppArgs[nPos] = alloca( 8 ), pUnoArgs[nPos], pParamTypeDescr,
161 311896 : pThis->getBridge()->getUno2Cpp() );
162 :
163 77974 : switch (pParamTypeDescr->eTypeClass)
164 : {
165 : case typelib_TypeClass_HYPER:
166 : case typelib_TypeClass_UNSIGNED_HYPER:
167 36 : INSERT_INT64( pCppArgs[nPos], nGPR, pGPR, pStack );
168 36 : break;
169 : case typelib_TypeClass_LONG:
170 : case typelib_TypeClass_UNSIGNED_LONG:
171 : case typelib_TypeClass_ENUM:
172 41260 : INSERT_INT32( pCppArgs[nPos], nGPR, pGPR, pStack );
173 41260 : break;
174 : case typelib_TypeClass_SHORT:
175 : case typelib_TypeClass_CHAR:
176 : case typelib_TypeClass_UNSIGNED_SHORT:
177 18314 : INSERT_INT16( pCppArgs[nPos], nGPR, pGPR, pStack );
178 18314 : break;
179 : case typelib_TypeClass_BOOLEAN:
180 : case typelib_TypeClass_BYTE:
181 15590 : INSERT_INT8( pCppArgs[nPos], nGPR, pGPR, pStack );
182 15590 : break;
183 : case typelib_TypeClass_FLOAT:
184 : case typelib_TypeClass_DOUBLE:
185 2774 : INSERT_FLOAT_DOUBLE( pCppArgs[nPos], nFPR, pFPR, pStack );
186 2774 : break;
187 : default:
188 0 : break;
189 : }
190 :
191 : // no longer needed
192 77974 : TYPELIB_DANGER_RELEASE( pParamTypeDescr );
193 : }
194 : else // ptr to complex value | ref
195 : {
196 257534 : if (! rParam.bIn) // is pure out
197 : {
198 : // cpp out is constructed mem, uno out is not!
199 : uno_constructData(
200 1216 : pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
201 1824 : pParamTypeDescr );
202 608 : pTempIndices[nTempIndices] = nPos; // default constructed for cpp call
203 : // will be released at reconversion
204 608 : ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
205 : }
206 : // is in/inout
207 256926 : else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
208 : {
209 : uno_copyAndConvertData(
210 118564 : pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
211 177846 : pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
212 :
213 59282 : pTempIndices[nTempIndices] = nPos; // has to be reconverted
214 : // will be released at reconversion
215 59282 : ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
216 : }
217 : else // direct way
218 : {
219 197644 : pCppArgs[nPos] = pUnoArgs[nPos];
220 : // no longer needed
221 197644 : TYPELIB_DANGER_RELEASE( pParamTypeDescr );
222 : }
223 257534 : INSERT_INT64( &(pCppArgs[nPos]), nGPR, pGPR, pStack );
224 : }
225 : }
226 :
227 : try
228 : {
229 : try {
230 : CPPU_CURRENT_NAMESPACE::callVirtualMethod(
231 : pAdjustedThisPtr, aVtableSlot.index,
232 : pCppReturn, pReturnTypeRef, bSimpleReturn,
233 419738 : pStackStart, ( pStack - pStackStart ),
234 419738 : pGPR, pFPR );
235 16060 : } catch (const Exception &) {
236 8030 : throw;
237 0 : } catch (const std::exception & e) {
238 0 : OUStringBuffer buf;
239 0 : buf.append("C++ code threw ");
240 0 : appendCString(buf, typeid(e).name());
241 0 : buf.append(": ");
242 0 : appendCString(buf, e.what());
243 0 : throw RuntimeException(buf.makeStringAndClear());
244 0 : } catch (...) {
245 0 : throw RuntimeException("C++ code threw unknown exception");
246 : }
247 :
248 411708 : *ppUnoExc = 0;
249 :
250 : // reconvert temporary params
251 882276 : for ( ; nTempIndices--; )
252 : {
253 58860 : sal_Int32 nIndex = pTempIndices[nTempIndices];
254 58860 : typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
255 :
256 58860 : if (pParams[nIndex].bIn)
257 : {
258 58252 : if (pParams[nIndex].bOut) // inout
259 : {
260 12 : uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
261 24 : uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
262 36 : pThis->getBridge()->getCpp2Uno() );
263 : }
264 : }
265 : else // pure out
266 : {
267 1216 : uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
268 1824 : pThis->getBridge()->getCpp2Uno() );
269 : }
270 : // destroy temp cpp param => cpp: every param was constructed
271 58860 : uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
272 :
273 58860 : TYPELIB_DANGER_RELEASE( pParamTypeDescr );
274 : }
275 : // return value
276 411708 : if (pCppReturn && pUnoReturn != pCppReturn)
277 : {
278 : uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
279 203662 : pThis->getBridge()->getCpp2Uno() );
280 203662 : uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
281 : }
282 : }
283 8030 : catch (...)
284 : {
285 : // fill uno exception
286 : #ifdef _LIBCPP_VERSION
287 : CPPU_CURRENT_NAMESPACE::fillUnoException(
288 : reinterpret_cast< __cxxabiv1::__cxa_eh_globals * >(
289 : __cxxabiv1::__cxa_get_globals())->caughtExceptions,
290 : *ppUnoExc, pThis->getBridge()->getCpp2Uno());
291 : #else
292 : fillUnoException(
293 : reinterpret_cast< CPPU_CURRENT_NAMESPACE::__cxa_eh_globals * >(
294 8030 : __cxxabiv1::__cxa_get_globals())->caughtExceptions,
295 16060 : *ppUnoExc, pThis->getBridge()->getCpp2Uno());
296 : #endif
297 :
298 : // temporary params
299 17090 : for ( ; nTempIndices--; )
300 : {
301 1030 : sal_Int32 nIndex = pTempIndices[nTempIndices];
302 : // destroy temp cpp param => cpp: every param was constructed
303 1030 : uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndices], cpp_release );
304 1030 : TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
305 : }
306 : // return type
307 8030 : if (pReturnTypeDescr)
308 8030 : TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
309 : }
310 419738 : }
311 :
312 :
313 : namespace bridges { namespace cpp_uno { namespace shared {
314 :
315 435671 : void unoInterfaceProxyDispatch(
316 : uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
317 : void * pReturn, void * pArgs[], uno_Any ** ppException )
318 : {
319 : // is my surrogate
320 : bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
321 435671 : = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
322 : #if OSL_DEBUG_LEVEL > 0
323 : typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
324 : #endif
325 :
326 435671 : switch (pMemberDescr->eTypeClass)
327 : {
328 : case typelib_TypeClass_INTERFACE_ATTRIBUTE:
329 : {
330 : #if OSL_DEBUG_LEVEL > 0
331 : // determine vtable call index
332 : sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition;
333 : OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### member pos out of range!" );
334 : #endif
335 : VtableSlot aVtableSlot(
336 : getVtableSlot(
337 : reinterpret_cast<
338 : typelib_InterfaceAttributeTypeDescription const * >(
339 15934 : pMemberDescr)));
340 :
341 15934 : if (pReturn)
342 : {
343 : // dependent dispatch
344 : cpp_call(
345 : pThis, aVtableSlot,
346 : ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
347 : 0, 0, // no params
348 13010 : pReturn, pArgs, ppException );
349 : }
350 : else
351 : {
352 : // is SET
353 : typelib_MethodParameter aParam;
354 : aParam.pTypeRef =
355 2924 : ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
356 2924 : aParam.bIn = sal_True;
357 2924 : aParam.bOut = sal_False;
358 :
359 2924 : typelib_TypeDescriptionReference * pReturnTypeRef = 0;
360 2924 : OUString aVoidName("void");
361 : typelib_typedescriptionreference_new(
362 2924 : &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
363 :
364 : // dependent dispatch
365 2924 : aVtableSlot.index += 1; // get, then set method
366 : cpp_call(
367 : pThis, aVtableSlot, // get, then set method
368 : pReturnTypeRef,
369 : 1, &aParam,
370 2924 : pReturn, pArgs, ppException );
371 :
372 2924 : typelib_typedescriptionreference_release( pReturnTypeRef );
373 : }
374 :
375 15934 : break;
376 : }
377 : case typelib_TypeClass_INTERFACE_METHOD:
378 : {
379 : #if OSL_DEBUG_LEVEL > 0
380 : // determine vtable call index
381 : sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition;
382 : OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### member pos out of range!" );
383 : #endif
384 : VtableSlot aVtableSlot(
385 : getVtableSlot(
386 : reinterpret_cast<
387 : typelib_InterfaceMethodTypeDescription const * >(
388 419737 : pMemberDescr)));
389 :
390 419737 : switch (aVtableSlot.index)
391 : {
392 : // standard calls
393 : case 1: // acquire uno interface
394 0 : (*pUnoI->acquire)( pUnoI );
395 0 : *ppException = 0;
396 0 : break;
397 : case 2: // release uno interface
398 0 : (*pUnoI->release)( pUnoI );
399 0 : *ppException = 0;
400 0 : break;
401 : case 0: // queryInterface() opt
402 : {
403 51703 : typelib_TypeDescription * pTD = 0;
404 51703 : TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() );
405 51703 : if (pTD)
406 : {
407 51703 : uno_Interface * pInterface = 0;
408 51703 : (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)(
409 : pThis->getBridge()->getUnoEnv(),
410 51703 : (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
411 :
412 51703 : if (pInterface)
413 : {
414 : ::uno_any_construct(
415 : reinterpret_cast< uno_Any * >( pReturn ),
416 15933 : &pInterface, pTD, 0 );
417 15933 : (*pInterface->release)( pInterface );
418 15933 : TYPELIB_DANGER_RELEASE( pTD );
419 15933 : *ppException = 0;
420 15933 : break;
421 : }
422 35770 : TYPELIB_DANGER_RELEASE( pTD );
423 : }
424 : } // else perform queryInterface()
425 : default:
426 : // dependent dispatch
427 : cpp_call(
428 : pThis, aVtableSlot,
429 : ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef,
430 : ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams,
431 : ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams,
432 403804 : pReturn, pArgs, ppException );
433 : }
434 419737 : break;
435 : }
436 : default:
437 : {
438 : ::com::sun::star::uno::RuntimeException aExc(
439 : OUString("illegal member type description!"),
440 0 : ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
441 :
442 0 : Type const & rExcType = ::getCppuType( &aExc );
443 : // binary identical null reference
444 0 : ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
445 : }
446 : }
447 435671 : }
448 :
449 : } } }
450 :
451 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|