LibreOffice Module bridges (master)  1
msvc_win32_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/config.h>
21 
22 #include <cassert>
23 
24 #include <malloc.h>
25 
26 #include <com/sun/star/uno/genfunc.hxx>
27 #include <uno/data.h>
28 
29 #include <bridge.hxx>
30 #include <types.hxx>
31 #include <unointerfaceproxy.hxx>
32 #include <vtables.hxx>
33 
34 #include <msvc/except.hxx>
35 
36 #if OSL_DEBUG_LEVEL > 1
37 #include <stdio.h>
38 #endif
39 
40 using namespace ::com::sun::star;
41 
42 namespace
43 {
44 
45 bool cpp_call(
48  typelib_TypeDescriptionReference * pReturnTypeRef,
49  sal_Int32 nParams,
50  typelib_MethodParameter * pParams,
51  void * pUnoReturn,
52  void * pUnoArgs[],
53  uno_Any ** ppUnoExc ) noexcept
54 {
55  const int MAXPARAMS = 32;
56 
57  if ( nParams > MAXPARAMS )
58  {
59  // We have a hard limit on the number of parameters so that we
60  // don't need any assembler code here but can call the
61  // function using normal C++.
62 
63  return false;
64  }
65 
66  // Table with this pointer, optional complex return value ptr, and the parameters
67  union {
68  sal_Int64 i;
69  void *p;
70  double d;
71  } aCppArgs[MAXPARAMS+2], uRetVal;
72  int nCppParamIndex = 0;
73 
74  // return type
75  typelib_TypeDescription * pReturnTD = nullptr;
76  TYPELIB_DANGER_GET( &pReturnTD, pReturnTypeRef );
77  assert(pReturnTD);
78 
79  // 'this'
80  void * pAdjustedThisPtr = reinterpret_cast<void **>( pThis->getCppI() ) + aVtableSlot.offset;
81  aCppArgs[nCppParamIndex++].p = pAdjustedThisPtr;
82 
83  enum class ReturnKind { Void, Simple, Complex, ComplexConvert };
84  ReturnKind retKind;
85  if (pUnoReturn == nullptr) {
86  retKind = ReturnKind::Void;
87  } else {
88  assert(pReturnTD != nullptr);
90  retKind = ReturnKind::Simple;
92  {
93  retKind = ReturnKind::ComplexConvert;
94  aCppArgs[nCppParamIndex++].p = alloca(pReturnTD->nSize);
95  } else {
96  retKind = ReturnKind::Complex;
97  aCppArgs[nCppParamIndex++].p = pUnoReturn;
98  }
99  }
100 
101  // indexes of values this have to be converted (interface conversion C++<=>UNO)
102  int pTempCppIndexes[MAXPARAMS];
103  int pTempIndexes[MAXPARAMS];
104  int nTempIndexes = 0;
105 
106  // type descriptions for reconversions
107  typelib_TypeDescription *pTempParamTD[MAXPARAMS];
108 
109  for (int nPos = 0; nPos < nParams; ++nPos, ++nCppParamIndex)
110  {
111  const typelib_MethodParameter & rParam = pParams[nPos];
112  typelib_TypeDescription * pParamTD = nullptr;
113  TYPELIB_DANGER_GET( &pParamTD, rParam.pTypeRef );
114 
115  if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType(pParamTD))
116  {
117  ::uno_copyAndConvertData(
118  &aCppArgs[nCppParamIndex], pUnoArgs[nPos], pParamTD,
119  pThis->getBridge()->getUno2Cpp() );
120 
121  // no longer needed
122  TYPELIB_DANGER_RELEASE( pParamTD );
123  }
124  else // ptr to complex value | ref
125  {
126  if (!rParam.bIn) // Is pure out
127  {
128  // C++ out is constructed mem, UNO out is not!
129  ::uno_constructData(
130  aCppArgs[nCppParamIndex].p = alloca( pParamTD->nSize ),
131  pParamTD );
132 
133  pTempCppIndexes[nTempIndexes] = nCppParamIndex;
134 
135  // default constructed for C++ call
136  pTempIndexes[nTempIndexes] = nPos;
137 
138  // will be released at reconversion
139  pTempParamTD[nTempIndexes++] = pParamTD;
140  }
141  // is in/inout
143  {
144  ::uno_copyAndConvertData(
145  aCppArgs[nCppParamIndex].p = alloca( pParamTD->nSize ),
146  pUnoArgs[nPos], pParamTD,
147  pThis->getBridge()->getUno2Cpp() );
148 
149  pTempCppIndexes[nTempIndexes] = nCppParamIndex;
150 
151  // has to be reconverted
152  pTempIndexes[nTempIndexes] = nPos;
153 
154  // will be released at reconversion
155  pTempParamTD[nTempIndexes++] = pParamTD;
156  }
157  else // direct way
158  {
159  aCppArgs[nCppParamIndex].p = pUnoArgs[nPos];
160  // no longer needed
161  TYPELIB_DANGER_RELEASE( pParamTD );
162  }
163  }
164  }
165 
166  __try
167  {
168  // The first real parameter is always 'this'.
169 
170  // The Windows x64 calling convention is very regular and
171  // elegant (even if perhaps then slightly slower than the
172  // Linux x64 one): The first four parameters, never more, are
173  // passed in registers, as long as they are a qword in size
174  // or less. (If larger, a pointer to a temp copy is passed, so
175  // it's equivalent anyway.) Floating point values are passed
176  // in XMM0..3 registers, others in RCX, RDX, R8, R9.
177 
178  // Now, the nice thing for us is that when calling varargs
179  // functions, floating-point parameters among the four first
180  // ones are always passed *both* in an XMM and integer
181  // register. So we don't need to bother here calling the
182  // method different ways depending on what types of parameters
183  // it actually expects. We just pretend parameters 3..4 are
184  // doubles, and they will be passed both in XMM and integer
185  // registers, and the callee will find them where it
186  // expects. (The callee is not actually varargs, of course.)
187 
188  sal_Int64 (*pIMethod)(sal_Int64, ...) =
189  reinterpret_cast<sal_Int64 (*)(sal_Int64, ...)>(
190  (*static_cast<sal_uInt64 **>(pAdjustedThisPtr))[aVtableSlot.index]);
191 
192  double (*pFMethod)(sal_Int64, ...) =
193  reinterpret_cast<double (*)(sal_Int64, ...)>(
194  (*static_cast<sal_uInt64 **>(pAdjustedThisPtr))[aVtableSlot.index]);
195 
196  // Pass parameters 2..4 as if it was a floating-point value so
197  // that it gets put in both XMM and integer registers per the
198  // calling convention. It doesn't matter if it actually is a
199  // fp or not.
200 
201  if ( pReturnTD &&
202  (pReturnTD->eTypeClass == typelib_TypeClass_FLOAT ||
203  pReturnTD->eTypeClass == typelib_TypeClass_DOUBLE) )
204  uRetVal.d =
205  pFMethod (aCppArgs[0].i, aCppArgs[1].d, aCppArgs[2].d, aCppArgs[3].d,
206  aCppArgs[4].i, aCppArgs[5].i, aCppArgs[6].i, aCppArgs[7].i,
207  aCppArgs[8].i, aCppArgs[9].i, aCppArgs[10].i, aCppArgs[11].i,
208  aCppArgs[12].i, aCppArgs[13].i, aCppArgs[14].i, aCppArgs[15].i,
209  aCppArgs[16].i, aCppArgs[17].i, aCppArgs[18].i, aCppArgs[19].i,
210  aCppArgs[20].i, aCppArgs[21].i, aCppArgs[22].i, aCppArgs[23].i,
211  aCppArgs[24].i, aCppArgs[25].i, aCppArgs[26].i, aCppArgs[27].i,
212  aCppArgs[28].i, aCppArgs[29].i, aCppArgs[30].i, aCppArgs[31].i );
213  else
214  uRetVal.i =
215  pIMethod (aCppArgs[0].i, aCppArgs[1].d, aCppArgs[2].d, aCppArgs[3].d,
216  aCppArgs[4].i, aCppArgs[5].i, aCppArgs[6].i, aCppArgs[7].i,
217  aCppArgs[8].i, aCppArgs[9].i, aCppArgs[10].i, aCppArgs[11].i,
218  aCppArgs[12].i, aCppArgs[13].i, aCppArgs[14].i, aCppArgs[15].i,
219  aCppArgs[16].i, aCppArgs[17].i, aCppArgs[18].i, aCppArgs[19].i,
220  aCppArgs[20].i, aCppArgs[21].i, aCppArgs[22].i, aCppArgs[23].i,
221  aCppArgs[24].i, aCppArgs[25].i, aCppArgs[26].i, aCppArgs[27].i,
222  aCppArgs[28].i, aCppArgs[29].i, aCppArgs[30].i, aCppArgs[31].i );
223  }
224  __except (msvc_filterCppException(
225  GetExceptionInformation(),
226  *ppUnoExc, pThis->getBridge()->getCpp2Uno() ))
227  {
228  // *ppUnoExc was constructed by filter function
229  // temporary params
230  while (nTempIndexes--)
231  {
232  int nCppIndex = pTempCppIndexes[nTempIndexes];
233  // destroy temp C++ param => C++: every param was constructed
234  ::uno_destructData(
235  aCppArgs[nCppIndex].p, pTempParamTD[nTempIndexes],
236  uno::cpp_release );
237  TYPELIB_DANGER_RELEASE( pTempParamTD[nTempIndexes] );
238  }
239 
240  // return type
241  if (pReturnTD)
242  TYPELIB_DANGER_RELEASE( pReturnTD );
243 
244  return true;
245  }
246 
247  // NO exception occurred
248  *ppUnoExc = nullptr;
249 
250  // reconvert temporary params
251  while (nTempIndexes--)
252  {
253  int nCppIndex = pTempCppIndexes[nTempIndexes];
254  int nIndex = pTempIndexes[nTempIndexes];
255  typelib_TypeDescription * pParamTD =
256  pTempParamTD[nTempIndexes];
257 
258  if (pParams[nIndex].bIn)
259  {
260  if (pParams[nIndex].bOut) // inout
261  {
262  ::uno_destructData(
263  pUnoArgs[nIndex], pParamTD, nullptr ); // destroy UNO value
264  ::uno_copyAndConvertData(
265  pUnoArgs[nIndex], aCppArgs[nCppIndex].p, pParamTD,
266  pThis->getBridge()->getCpp2Uno() );
267  }
268  }
269  else // pure out
270  {
271  ::uno_copyAndConvertData(
272  pUnoArgs[nIndex], aCppArgs[nCppIndex].p, pParamTD,
273  pThis->getBridge()->getCpp2Uno() );
274  }
275 
276  // destroy temp C++ param => C++: every param was constructed
277  ::uno_destructData(
278  aCppArgs[nCppIndex].p, pParamTD, uno::cpp_release );
279 
280  TYPELIB_DANGER_RELEASE( pParamTD );
281  }
282 
283  // return value
284  switch (retKind) {
285  case ReturnKind::Void:
286  break;
287  case ReturnKind::Simple:
288  *static_cast<sal_Int64*>(pUnoReturn) = uRetVal.i;
289  break;
290  case ReturnKind::Complex:
291  assert(uRetVal.p == pUnoReturn);
292  break;
293  case ReturnKind::ComplexConvert:
294  assert(uRetVal.p == aCppArgs[1].p);
295  ::uno_copyAndConvertData(
296  pUnoReturn, uRetVal.p, pReturnTD,
297  pThis->getBridge()->getCpp2Uno() );
298  ::uno_destructData(
299  uRetVal.p, pReturnTD, uno::cpp_release );
300  break;
301  }
302 
303  // return type
304  if ( pReturnTD )
305  TYPELIB_DANGER_RELEASE( pReturnTD );
306 
307  return true;
308 }
309 
310 } // namespace
311 
312 namespace bridges::cpp_uno::shared {
313 
315  uno_Interface * pUnoI,
316  const typelib_TypeDescription * pMemberTD,
317  void * pReturn,
318  void * pArgs[],
319  uno_Any ** ppException )
320 {
321  // is my surrogate
323  = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
324 #if OSL_DEBUG_LEVEL > 0
325  typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
326 #endif
327 
328  switch (pMemberTD->eTypeClass)
329  {
330  case typelib_TypeClass_INTERFACE_ATTRIBUTE:
331  {
332 #if OSL_DEBUG_LEVEL > 0
333  // determine vtable call index
334  sal_Int32 nMemberPos = reinterpret_cast<typelib_InterfaceMemberTypeDescription const *>(pMemberTD)->nPosition;
335  assert(nMemberPos < pTypeDescr->nAllMembers);
336 #endif
337  VtableSlot aVtableSlot(
339  reinterpret_cast<
340  typelib_InterfaceAttributeTypeDescription const * >(
341  pMemberTD)));
342  if ( pReturn )
343  {
344  // is GET
345  cpp_call(
346  pThis, aVtableSlot,
347  reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>(pMemberTD)->pAttributeTypeRef,
348  0, nullptr, // no params
349  pReturn, pArgs, ppException );
350  }
351  else
352  {
353  // is SET
354  typelib_MethodParameter aParam;
355  aParam.pTypeRef =
356  reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>(pMemberTD)->pAttributeTypeRef;
357  aParam.bIn = true;
358  aParam.bOut = false;
359 
360  typelib_TypeDescriptionReference * pReturnTypeRef = nullptr;
361  OUString aVoidName("void");
363  &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
364 
365  aVtableSlot.index += 1; // get, then set method
366  cpp_call(
367  pThis, aVtableSlot,
368  pReturnTypeRef,
369  1, &aParam,
370  pReturn, pArgs, ppException );
371 
373  }
374 
375  break;
376  }
377  case typelib_TypeClass_INTERFACE_METHOD:
378  {
379 #if OSL_DEBUG_LEVEL > 0
380  // determine vtable call index
381  sal_Int32 nMemberPos = reinterpret_cast<typelib_InterfaceMemberTypeDescription const *>(pMemberTD)->nPosition;
382  assert(nMemberPos < pTypeDescr->nAllMembers);
383 #endif
384  VtableSlot aVtableSlot(
386  reinterpret_cast<
387  typelib_InterfaceMethodTypeDescription const * >(
388  pMemberTD)));
389 
390  switch (aVtableSlot.index)
391  {
392  case 1: // acquire UNO interface
393  (*pUnoI->acquire)( pUnoI );
394  *ppException = nullptr;
395  break;
396  case 2: // release UNO interface
397  (*pUnoI->release)( pUnoI );
398  *ppException = nullptr;
399  break;
400  case 0: // queryInterface() opt
401  {
402  typelib_TypeDescription * pTD = nullptr;
403  TYPELIB_DANGER_GET( &pTD, static_cast< uno::Type * >( pArgs[0] )->getTypeLibType() );
404 
405  if ( pTD )
406  {
407  uno_Interface * pInterface = nullptr;
408  (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)(
409  pThis->getBridge()->getUnoEnv(),
410  reinterpret_cast<void **>(&pInterface), pThis->oid.pData, reinterpret_cast<typelib_InterfaceTypeDescription *>(pTD) );
411 
412  if ( pInterface )
413  {
414  ::uno_any_construct(
415  static_cast< uno_Any * >( pReturn ),
416  &pInterface, pTD, nullptr );
417  (*pInterface->release)( pInterface );
418  TYPELIB_DANGER_RELEASE( pTD );
419  *ppException = nullptr;
420  break;
421  }
422  TYPELIB_DANGER_RELEASE( pTD );
423  }
424  [[fallthrough]]; // else perform queryInterface()
425  }
426  default:
427  typelib_InterfaceMethodTypeDescription const* pMethodTD
428  = reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberTD);
429 
430  if (!cpp_call(pThis, aVtableSlot, pMethodTD->pReturnTypeRef, pMethodTD->nParams,
431  pMethodTD->pParams, pReturn, pArgs, ppException))
432  {
433  uno::RuntimeException aExc( "Too many parameters!" );
434 
435  uno::Type const & rExcType = cppu::UnoType<decltype(aExc)>::get();
436  ::uno_type_any_construct(*ppException, &aExc, rExcType.getTypeLibType(), nullptr);
437  }
438  }
439  break;
440  }
441  default:
442  {
443  uno::RuntimeException aExc("Illegal member type description!", uno::Reference<uno::XInterface>());
444 
445  uno::Type const & rExcType = cppu::UnoType<decltype(aExc)>::get();
446  // binary identical null reference
447  ::uno_type_any_construct(*ppException, &aExc, rExcType.getTypeLibType(), nullptr);
448  }
449  }
450 }
451 
452 }
453 
454 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_Int32 nIndex
Represents a vtable slot of a C++ class.
Definition: vtables.hxx:59
int msvc_filterCppException(EXCEPTION_POINTERS *pPointers, uno_Any *pUnoExc, 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
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)
uno_ExtEnvironment * getUnoEnv()
Definition: bridge.hxx:70
struct _uno_Any uno_Any
Definition: msvc/except.hxx:31
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)
int i
typelib_InterfaceTypeDescription * pTypeDescr
void SAL_CALL typelib_typedescriptionreference_release(typelib_TypeDescriptionReference *pRef) SAL_THROW_EXTERN_C()
struct _typelib_TypeDescription typelib_TypeDescription
Definition: msvc/except.hxx:52
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()
double d
void * p
sal_uInt16 nPos