LibreOffice Module bridges (master)  1
gcc3_linux_x86-64/uno2cpp.cxx
Go to the documentation of this file.
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 #include <sal/alloca.h>
21 
22 #include <exception>
23 #include <typeinfo>
24 
25 #include <rtl/alloc.h>
26 
27 #include <com/sun/star/uno/genfunc.hxx>
28 #include <com/sun/star/uno/RuntimeException.hpp>
30 #include <uno/data.h>
31 
32 #include <bridge.hxx>
33 #include <types.hxx>
34 #include <unointerfaceproxy.hxx>
35 #include <vtables.hxx>
36 
37 #include "abi.hxx"
38 #include "callvirtualmethod.hxx"
39 #include "share.hxx"
40 
41 using namespace ::com::sun::star::uno;
42 
43 namespace {
44 
45 // Functions for easier insertion of values to registers or stack
46 // pSV - pointer to the source
47 // nr - order of the value [will be increased if stored to register]
48 // pFPR, pGPR - pointer to the registers
49 // pDS - pointer to the stack [will be increased if stored here]
50 
51 // The value in %xmm register is already prepared to be retrieved as a float,
52 // thus we treat float and double the same
54  void const * pSV, sal_uInt32 & nr, double * pFPR, sal_uInt64 *& pDS)
55 {
56  if ( nr < x86_64::MAX_SSE_REGS )
57  pFPR[nr++] = *static_cast<double const *>( pSV );
58  else
59  *pDS++ = *static_cast<sal_uInt64 const *>( pSV ); // verbatim!
60 }
61 
62 void INSERT_INT64(
63  void const * pSV, sal_uInt32 & nr, sal_uInt64 * pGPR, sal_uInt64 *& pDS)
64 {
65  if ( nr < x86_64::MAX_GPR_REGS )
66  pGPR[nr++] = *static_cast<sal_uInt64 const *>( pSV );
67  else
68  *pDS++ = *static_cast<sal_uInt64 const *>( pSV );
69 }
70 
71 void INSERT_INT32(
72  void const * pSV, sal_uInt32 & nr, sal_uInt64 * pGPR, sal_uInt64 *& pDS)
73 {
74  if ( nr < x86_64::MAX_GPR_REGS )
75  pGPR[nr++] = *static_cast<sal_uInt32 const *>( pSV );
76  else
77  *pDS++ = *static_cast<sal_uInt32 const *>( pSV );
78 }
79 
80 void INSERT_INT16(
81  void const * pSV, sal_uInt32 & nr, sal_uInt64 * pGPR, sal_uInt64 *& pDS)
82 {
83  if ( nr < x86_64::MAX_GPR_REGS )
84  pGPR[nr++] = *static_cast<sal_uInt16 const *>( pSV );
85  else
86  *pDS++ = *static_cast<sal_uInt16 const *>( pSV );
87 }
88 
89 void INSERT_INT8(
90  void const * pSV, sal_uInt32 & nr, sal_uInt64 * pGPR, sal_uInt64 *& pDS)
91 {
92  if ( nr < x86_64::MAX_GPR_REGS )
93  pGPR[nr++] = *static_cast<sal_uInt8 const *>( pSV );
94  else
95  *pDS++ = *static_cast<sal_uInt8 const *>( pSV );
96 }
97 
98 }
99 
100 static void cpp_call(
103  typelib_TypeDescriptionReference * pReturnTypeRef,
104  sal_Int32 nParams, typelib_MethodParameter * pParams,
105  void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
106 {
107  // Maximum space for [complex ret ptr], values | ptr ...
108  // (but will be used less - some of the values will be in pGPR and pFPR)
109  sal_uInt64 *pStack = static_cast<sal_uInt64 *>(__builtin_alloca( (nParams + 3) * sizeof(sal_uInt64) ));
110  sal_uInt64 *pStackStart = pStack;
111 
112  sal_uInt64 pGPR[x86_64::MAX_GPR_REGS];
113  sal_uInt32 nGPR = 0;
114 
115  double pFPR[x86_64::MAX_SSE_REGS];
116  sal_uInt32 nFPR = 0;
117 
118  // Return
119  typelib_TypeDescription * pReturnTypeDescr = nullptr;
120  TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
121  assert(pReturnTypeDescr);
122 
123  void * pCppReturn = nullptr; // if != 0 && != pUnoReturn, needs reconversion (see below)
124 
125  bool bSimpleReturn = true;
126  if ( pReturnTypeDescr )
127  {
128  if ( x86_64::return_in_hidden_param( pReturnTypeRef ) )
129  bSimpleReturn = false;
130 
131  if ( bSimpleReturn )
132  pCppReturn = pUnoReturn; // direct way for simple types
133  else
134  {
135  // complex return via ptr
136  pCppReturn = bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )?
137  __builtin_alloca( pReturnTypeDescr->nSize ) : pUnoReturn;
138  INSERT_INT64( &pCppReturn, nGPR, pGPR, pStack );
139  }
140  }
141 
142  // Push "this" pointer
143  void * pAdjustedThisPtr = reinterpret_cast< void ** >( pThis->getCppI() ) + aVtableSlot.offset;
144  INSERT_INT64( &pAdjustedThisPtr, nGPR, pGPR, pStack );
145 
146  // Args
147  void ** pCppArgs = static_cast<void **>(alloca( 3 * sizeof(void *) * nParams ));
148  // Indices of values this have to be converted (interface conversion cpp<=>uno)
149  sal_Int32 * pTempIndices = reinterpret_cast<sal_Int32 *>(pCppArgs + nParams);
150  // Type descriptions for reconversions
151  typelib_TypeDescription ** ppTempParamTypeDescr = reinterpret_cast<typelib_TypeDescription **>(pCppArgs + (2 * nParams));
152 
153  sal_Int32 nTempIndices = 0;
154 
155  for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
156  {
157  const typelib_MethodParameter & rParam = pParams[nPos];
158  typelib_TypeDescription * pParamTypeDescr = nullptr;
159  TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
160 
161  if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
162  {
163  pCppArgs[nPos] = alloca( 8 );
164  uno_copyAndConvertData( pCppArgs[nPos], pUnoArgs[nPos], pParamTypeDescr,
165  pThis->getBridge()->getUno2Cpp() );
166 
167  switch (pParamTypeDescr->eTypeClass)
168  {
169  case typelib_TypeClass_HYPER:
170  case typelib_TypeClass_UNSIGNED_HYPER:
171  INSERT_INT64( pCppArgs[nPos], nGPR, pGPR, pStack );
172  break;
173  case typelib_TypeClass_LONG:
174  case typelib_TypeClass_UNSIGNED_LONG:
175  case typelib_TypeClass_ENUM:
176  INSERT_INT32( pCppArgs[nPos], nGPR, pGPR, pStack );
177  break;
178  case typelib_TypeClass_SHORT:
179  case typelib_TypeClass_CHAR:
180  case typelib_TypeClass_UNSIGNED_SHORT:
181  INSERT_INT16( pCppArgs[nPos], nGPR, pGPR, pStack );
182  break;
183  case typelib_TypeClass_BOOLEAN:
184  case typelib_TypeClass_BYTE:
185  INSERT_INT8( pCppArgs[nPos], nGPR, pGPR, pStack );
186  break;
187  case typelib_TypeClass_FLOAT:
188  case typelib_TypeClass_DOUBLE:
189  INSERT_FLOAT_DOUBLE( pCppArgs[nPos], nFPR, pFPR, pStack );
190  break;
191  default:
192  break;
193  }
194 
195  // no longer needed
196  TYPELIB_DANGER_RELEASE( pParamTypeDescr );
197  }
198  else // ptr to complex value | ref
199  {
200  if (! rParam.bIn) // is pure out
201  {
202  // cpp out is constructed mem, uno out is not!
203  pCppArgs[nPos] = alloca( pParamTypeDescr->nSize );
204  uno_constructData( pCppArgs[nPos], pParamTypeDescr );
205  pTempIndices[nTempIndices] = nPos; // default constructed for cpp call
206  // will be released at reconversion
207  ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
208  }
209  // is in/inout
210  else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
211  {
212  pCppArgs[nPos] = alloca( pParamTypeDescr->nSize );
214  pCppArgs[nPos], pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
215 
216  pTempIndices[nTempIndices] = nPos; // has to be reconverted
217  // will be released at reconversion
218  ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
219  }
220  else // direct way
221  {
222  pCppArgs[nPos] = pUnoArgs[nPos];
223  // no longer needed
224  TYPELIB_DANGER_RELEASE( pParamTypeDescr );
225  }
226  INSERT_INT64( &(pCppArgs[nPos]), nGPR, pGPR, pStack );
227  }
228  }
229 
230  try
231  {
232  try {
234  pAdjustedThisPtr, aVtableSlot.index,
235  pCppReturn, pReturnTypeRef, bSimpleReturn,
236  pStackStart, ( pStack - pStackStart ),
237  pGPR, pFPR );
238  } catch (const Exception &) {
239  throw;
240  } catch (const std::exception & e) {
241  throw RuntimeException(
242  "C++ code threw " + o3tl::runtimeToOUString(typeid(e).name())
243  + ": " + o3tl::runtimeToOUString(e.what()));
244  } catch (...) {
245  throw RuntimeException("C++ code threw unknown exception");
246  }
247 
248  *ppUnoExc = nullptr;
249 
250  // reconvert temporary params
251  for ( ; nTempIndices--; )
252  {
253  sal_Int32 nIndex = pTempIndices[nTempIndices];
254  typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
255 
256  if (pParams[nIndex].bIn)
257  {
258  if (pParams[nIndex].bOut) // inout
259  {
260  uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, nullptr ); // destroy uno value
261  uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
262  pThis->getBridge()->getCpp2Uno() );
263  }
264  }
265  else // pure out
266  {
267  uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
268  pThis->getBridge()->getCpp2Uno() );
269  }
270  // destroy temp cpp param => cpp: every param was constructed
271  uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
272 
273  TYPELIB_DANGER_RELEASE( pParamTypeDescr );
274  }
275  // return value
276  if (pCppReturn && pUnoReturn != pCppReturn)
277  {
278  uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
279  pThis->getBridge()->getCpp2Uno() );
280  uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
281  }
282  }
283  catch (...)
284  {
285  // fill uno exception
287 
288  // temporary params
289  for ( ; nTempIndices--; )
290  {
291  sal_Int32 nIndex = pTempIndices[nTempIndices];
292  // destroy temp cpp param => cpp: every param was constructed
293  uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndices], cpp_release );
294  TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
295  }
296  // return type
297  if (pReturnTypeDescr)
298  TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
299  }
300 }
301 
302 
303 namespace bridges::cpp_uno::shared {
304 
306  uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
307  void * pReturn, void * pArgs[], uno_Any ** ppException )
308 {
309  // is my surrogate
311  = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
312 
313  switch (pMemberDescr->eTypeClass)
314  {
315  case typelib_TypeClass_INTERFACE_ATTRIBUTE:
316  {
317  assert(
318  (reinterpret_cast<typelib_InterfaceMemberTypeDescription const *>(pMemberDescr)
319  ->nPosition)
320  < pThis->pTypeDescr->nAllMembers);
321  VtableSlot aVtableSlot(
323  reinterpret_cast<
324  typelib_InterfaceAttributeTypeDescription const * >(
325  pMemberDescr)));
326 
327  if (pReturn)
328  {
329  // dependent dispatch
330  cpp_call(
331  pThis, aVtableSlot,
332  reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>(pMemberDescr)->pAttributeTypeRef,
333  0, nullptr, // no params
334  pReturn, pArgs, ppException );
335  }
336  else
337  {
338  // is SET
339  typelib_MethodParameter aParam;
340  aParam.pTypeRef =
341  reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>(pMemberDescr)->pAttributeTypeRef;
342  aParam.bIn = true;
343  aParam.bOut = false;
344 
345  typelib_TypeDescriptionReference * pReturnTypeRef = nullptr;
346  OUString aVoidName("void");
348  &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
349 
350  // dependent dispatch
351  aVtableSlot.index += 1; // get, then set method
352  cpp_call(
353  pThis, aVtableSlot, // get, then set method
354  pReturnTypeRef,
355  1, &aParam,
356  pReturn, pArgs, ppException );
357 
359  }
360 
361  break;
362  }
363  case typelib_TypeClass_INTERFACE_METHOD:
364  {
365  assert(
366  (reinterpret_cast<typelib_InterfaceMemberTypeDescription const *>(pMemberDescr)
367  ->nPosition)
368  < pThis->pTypeDescr->nAllMembers);
369  VtableSlot aVtableSlot(
371  reinterpret_cast<
372  typelib_InterfaceMethodTypeDescription const * >(
373  pMemberDescr)));
374 
375  switch (aVtableSlot.index)
376  {
377  // standard calls
378  case 1: // acquire uno interface
379  (*pUnoI->acquire)( pUnoI );
380  *ppException = nullptr;
381  break;
382  case 2: // release uno interface
383  (*pUnoI->release)( pUnoI );
384  *ppException = nullptr;
385  break;
386  case 0: // queryInterface() opt
387  {
388  typelib_TypeDescription * pTD = nullptr;
389  TYPELIB_DANGER_GET( &pTD, static_cast< Type * >( pArgs[0] )->getTypeLibType() );
390  if (pTD)
391  {
392  uno_Interface * pInterface = nullptr;
393  (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)(
394  pThis->getBridge()->getUnoEnv(),
395  reinterpret_cast<void **>(&pInterface), pThis->oid.pData, reinterpret_cast<typelib_InterfaceTypeDescription *>(pTD) );
396 
397  if (pInterface)
398  {
399  ::uno_any_construct(
400  static_cast< uno_Any * >( pReturn ),
401  &pInterface, pTD, nullptr );
402  (*pInterface->release)( pInterface );
403  TYPELIB_DANGER_RELEASE( pTD );
404  *ppException = nullptr;
405  break;
406  }
407  TYPELIB_DANGER_RELEASE( pTD );
408  }
409  [[fallthrough]]; // else perform queryInterface()
410  }
411  default:
412  // dependent dispatch
413  cpp_call(
414  pThis, aVtableSlot,
415  reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberDescr)->pReturnTypeRef,
416  reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberDescr)->nParams,
417  reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberDescr)->pParams,
418  pReturn, pArgs, ppException );
419  }
420  break;
421  }
422  default:
423  {
424  ::com::sun::star::uno::RuntimeException aExc(
425  "illegal member type description!",
427 
428  Type const & rExcType = cppu::UnoType<decltype(aExc)>::get();
429  // binary identical null reference
430  ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), nullptr );
431  }
432  }
433 }
434 
435 }
436 
437 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const sal_uInt32 MAX_GPR_REGS
Type
#define INSERT_FLOAT_DOUBLE(pSV, nr, pFPR, pDS)
sal_Int32 nIndex
void SAL_CALL uno_destructData(void *pValue, typelib_TypeDescription *pTypeDescr, uno_ReleaseFunc release) SAL_THROW_EXTERN_C()
Represents a vtable slot of a C++ class.
Definition: vtables.hxx:59
void fillUnoException(uno_Any *pExc, uno_Mapping *pCpp2Uno)
bool isSimpleType(typelib_TypeClass typeClass)
Determines whether a type is a "simple" type (VOID, BOOLEAN, BYTE, SHORT, UNSIGNED SHORT...
Definition: types.cxx:28
#define INSERT_INT32(pSV, pDS)
void callVirtualMethod(void *pAdjustedThisPtr, sal_Int32 nVtableIndex, void *pRegisterReturn, typelib_TypeDescription *pReturnTypeDescr, bool bSimpleReturn, sal_Int32 *pStackLongs, sal_Int32 nStackLongs)
sal_Int32 index
The index within the vtable.
Definition: vtables.hxx:76
A uno proxy wrapping a cpp interface.
bool relatesToInterfaceType(typelib_TypeDescription const *type)
Determines whether a type relates to an interface type (is itself an interface type, or might contain entities of interface type).
Definition: types.cxx:41
void unoInterfaceProxyDispatch(uno_Interface *pUnoI, const typelib_TypeDescription *pMemberDescr, void *pReturn, void *pArgs[], uno_Any **ppException)
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
uno_ExtEnvironment * getUnoEnv()
Definition: bridge.hxx:70
struct _uno_Any uno_Any
Definition: msvc/except.hxx:31
uno_Mapping * getUno2Cpp()
Definition: bridge.hxx:73
static void 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)
#define INSERT_INT8(pSV, pDS)
sal_Int32 offset
The offset of the vtable.
Definition: vtables.hxx:68
typelib_InterfaceTypeDescription * pTypeDescr
void SAL_CALL uno_constructData(void *pMem, typelib_TypeDescription *pTypeDescr) SAL_THROW_EXTERN_C()
void SAL_CALL uno_copyAndConvertData(void *pDest, void *pSource, typelib_TypeDescription *pTypeDescr, uno_Mapping *mapping) SAL_THROW_EXTERN_C()
void SAL_CALL typelib_typedescriptionreference_release(typelib_TypeDescriptionReference *pRef) SAL_THROW_EXTERN_C()
#define INSERT_INT64(pSV, pDS)
struct _typelib_TypeDescription typelib_TypeDescription
Definition: msvc/except.hxx:52
uno_Mapping * getCpp2Uno()
Definition: bridge.hxx:72
VtableSlot getVtableSlot(typelib_InterfaceAttributeTypeDescription const *ifcMember)
Calculates the vtable slot associated with an interface attribute member.
Definition: vtables.cxx:132
void SAL_CALL typelib_typedescriptionreference_new(typelib_TypeDescriptionReference **ppTDR, typelib_TypeClass eTypeClass, rtl_uString *pTypeName) SAL_THROW_EXTERN_C()
const sal_uInt32 MAX_SSE_REGS
OUString runtimeToOUString(char const *runtimeString)
unsigned char sal_uInt8
#define INSERT_INT16(pSV, pDS)
bool return_in_hidden_param(typelib_TypeDescriptionReference *pTypeRef) noexcept
Does function that returns this type use a hidden parameter, or registers?
com::sun::star::uno::XInterface * getCppI()
sal_uInt16 nPos
char const * name