LibreOffice Module bridges (master)  1
gcc3_linux_aarch64/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 #include <cstring>
24 #include <exception>
25 #include <typeinfo>
26 
27 #include <bridge.hxx>
28 #include <types.hxx>
29 #include <unointerfaceproxy.hxx>
30 #include <vtables.hxx>
31 #include <com/sun/star/uno/Exception.hpp>
32 #include <com/sun/star/uno/RuntimeException.hpp>
33 #include <com/sun/star/uno/genfunc.hxx>
34 #include <rtl/textenc.h>
35 #include <rtl/ustring.hxx>
36 #include <sal/alloca.h>
37 #include <sal/types.h>
38 #include <typelib/typeclass.h>
39 #include <typelib/typedescription.h>
40 #include <uno/any2.h>
41 #include <uno/data.h>
42 
43 #include "abi.hxx"
44 #include "callvirtualfunction.hxx"
45 
46 namespace {
47 
48 void pushArgument(
49 #ifdef MACOSX
50  typelib_TypeClass typeclass,
51  sal_Int32 * const subsp,
52 #endif
53  unsigned long value, unsigned long * const stack, sal_Int32 * const sp,
54  unsigned long * const regs, sal_Int32 * const nregs)
55 {
56 #ifdef MACOSX
57  if (*nregs != 8)
58  {
59  regs[(*nregs)++] = value;
60  }
61  else
62  {
63  switch (typeclass) {
64  case typelib_TypeClass_BOOLEAN:
65  case typelib_TypeClass_BYTE:
66  *reinterpret_cast<uint8_t*>(reinterpret_cast<uintptr_t>(stack + *sp) + *subsp) = value;
67  (*subsp) += 1;
68  if (*subsp == 8)
69  {
70  (*sp)++;
71  *subsp = 0;
72  }
73  break;
74  case typelib_TypeClass_SHORT:
75  case typelib_TypeClass_UNSIGNED_SHORT:
76  case typelib_TypeClass_CHAR:
77  *subsp = (*subsp + 1) & ~0x1;
78  if (*subsp == 8)
79  {
80  (*sp)++;
81  *subsp = 0;
82  }
83  *reinterpret_cast<uint16_t*>(reinterpret_cast<uintptr_t>(stack + *sp) + *subsp) = value;
84  (*subsp) += 2;
85  if (*subsp == 8)
86  {
87  (*sp)++;
88  *subsp = 0;
89  }
90  break;
91  case typelib_TypeClass_LONG:
92  case typelib_TypeClass_UNSIGNED_LONG:
93  case typelib_TypeClass_ENUM:
94  case typelib_TypeClass_FLOAT:
95  *subsp = (*subsp + 3) & ~0x3;
96  if (*subsp == 8)
97  {
98  (*sp)++;
99  *subsp = 0;
100  }
101  *reinterpret_cast<uint32_t*>(reinterpret_cast<uintptr_t>(stack + *sp) + *subsp) = value;
102  (*subsp) += 4;
103  if (*subsp == 8)
104  {
105  (*sp)++;
106  *subsp = 0;
107  }
108  break;
109  case typelib_TypeClass_HYPER:
110  case typelib_TypeClass_UNSIGNED_HYPER:
111  default:
112  if (*subsp > 0)
113  {
114  (*sp)++;
115  *subsp = 0;
116  }
117  stack[*sp] = value;
118  (*sp)++;
119  break;
120  }
121  }
122 #else
123  (*nregs != 8 ? regs[(*nregs)++] : stack[(*sp)++]) = value;
124 #endif
125 }
126 
127 void call(
130  typelib_TypeDescriptionReference * returnType, sal_Int32 count,
131  typelib_MethodParameter * parameters, void * returnValue, void ** arguments,
132  uno_Any ** exception)
133 {
134  typelib_TypeDescription * rtd = nullptr;
135  TYPELIB_DANGER_GET(&rtd, returnType);
138  void * ret = retConv ? alloca(rtd->nSize) : returnValue;
139  unsigned long ** thisPtr
140  = reinterpret_cast<unsigned long **>(proxy->getCppI()) + slot.offset;
141  unsigned long * stack = static_cast<unsigned long *>(
142  alloca(count * sizeof (unsigned long)));
143  sal_Int32 sp = 0;
144 #ifdef MACOSX
145  sal_Int32 subsp = 0;
146 #endif
147  unsigned long gpr[8];
148  sal_Int32 ngpr = 0;
149  unsigned long fpr[8];
150  sal_Int32 nfpr = 0;
151  gpr[ngpr++] = reinterpret_cast<unsigned long>(thisPtr);
152  void ** cppArgs = static_cast<void **>(alloca(count * sizeof (void *)));
153  typelib_TypeDescription ** ptds =
154  static_cast<typelib_TypeDescription **>(
155  alloca(count * sizeof (typelib_TypeDescription *)));
156  for (sal_Int32 i = 0; i != count; ++i) {
157  if (!parameters[i].bOut &&
158  bridges::cpp_uno::shared::isSimpleType(parameters[i].pTypeRef))
159  {
160  cppArgs[i] = nullptr;
161  switch (parameters[i].pTypeRef->eTypeClass) {
162  case typelib_TypeClass_BOOLEAN:
163  pushArgument(
164 #ifdef MACOSX
165  parameters[i].pTypeRef->eTypeClass, &subsp,
166 #endif
167  static_cast<unsigned long>(*static_cast<sal_Bool *>(arguments[i])), stack, &sp,
168  gpr, &ngpr);
169  break;
170  case typelib_TypeClass_BYTE:
171  pushArgument(
172 #ifdef MACOSX
173  parameters[i].pTypeRef->eTypeClass, &subsp,
174 #endif
175  *static_cast<sal_Int8 *>(arguments[i]), stack, &sp, gpr,
176  &ngpr);
177  break;
178  case typelib_TypeClass_SHORT:
179  pushArgument(
180 #ifdef MACOSX
181  parameters[i].pTypeRef->eTypeClass, &subsp,
182 #endif
183  *static_cast<sal_Int16 *>(arguments[i]), stack, &sp, gpr,
184  &ngpr);
185  break;
186  case typelib_TypeClass_UNSIGNED_SHORT:
187  pushArgument(
188 #ifdef MACOSX
189  parameters[i].pTypeRef->eTypeClass, &subsp,
190 #endif
191  *static_cast<sal_uInt16 *>(arguments[i]), stack, &sp, gpr,
192  &ngpr);
193  break;
194  case typelib_TypeClass_LONG:
195  case typelib_TypeClass_ENUM:
196  pushArgument(
197 #ifdef MACOSX
198  parameters[i].pTypeRef->eTypeClass, &subsp,
199 #endif
200  *static_cast<sal_Int32 *>(arguments[i]), stack, &sp, gpr,
201  &ngpr);
202  break;
203  case typelib_TypeClass_UNSIGNED_LONG:
204  pushArgument(
205 #ifdef MACOSX
206  parameters[i].pTypeRef->eTypeClass, &subsp,
207 #endif
208  *static_cast<sal_uInt32 *>(arguments[i]), stack, &sp, gpr,
209  &ngpr);
210  break;
211  case typelib_TypeClass_HYPER:
212  pushArgument(
213 #ifdef MACOSX
214  parameters[i].pTypeRef->eTypeClass, &subsp,
215 #endif
216  *static_cast<sal_Int64 *>(arguments[i]), stack, &sp, gpr,
217  &ngpr);
218  break;
219  case typelib_TypeClass_UNSIGNED_HYPER:
220  pushArgument(
221 #ifdef MACOSX
222  parameters[i].pTypeRef->eTypeClass, &subsp,
223 #endif
224  *static_cast<sal_uInt64 *>(arguments[i]), stack, &sp, gpr,
225  &ngpr);
226  break;
227  case typelib_TypeClass_FLOAT:
228  pushArgument(
229 #ifdef MACOSX
230  parameters[i].pTypeRef->eTypeClass, &subsp,
231 #endif
232  *static_cast<unsigned int *>(arguments[i]), stack, &sp, fpr,
233  &nfpr);
234  break;
235  case typelib_TypeClass_DOUBLE:
236  pushArgument(
237 #ifdef MACOSX
238  parameters[i].pTypeRef->eTypeClass, &subsp,
239 #endif
240  *static_cast<unsigned long *>(arguments[i]), stack, &sp,
241  fpr, &nfpr);
242  break;
243  case typelib_TypeClass_CHAR:
244  pushArgument(
245 #ifdef MACOSX
246  parameters[i].pTypeRef->eTypeClass, &subsp,
247 #endif
248  *static_cast<sal_Unicode *>(arguments[i]), stack, &sp, gpr,
249  &ngpr);
250  break;
251  default:
252  assert(false);
253  }
254  } else {
255  typelib_TypeDescription * ptd = nullptr;
256  TYPELIB_DANGER_GET(&ptd, parameters[i].pTypeRef);
257  if (!parameters[i].bIn) {
258  cppArgs[i] = alloca(ptd->nSize);
259  uno_constructData(cppArgs[i], ptd);
260  ptds[i] = ptd;
261  pushArgument(
262 #ifdef MACOSX
263  typelib_TypeClass_HYPER, &subsp,
264 #endif
265  reinterpret_cast<unsigned long>(cppArgs[i]), stack, &sp,
266  gpr, &ngpr);
268  cppArgs[i] = alloca(ptd->nSize);
270  cppArgs[i], arguments[i], ptd,
271  proxy->getBridge()->getUno2Cpp());
272  ptds[i] = ptd;
273  pushArgument(
274 #ifdef MACOSX
275  typelib_TypeClass_HYPER, &subsp,
276 #endif
277  reinterpret_cast<unsigned long>(cppArgs[i]), stack, &sp,
278  gpr, &ngpr);
279  } else {
280  cppArgs[i] = nullptr;
281  pushArgument(
282 #ifdef MACOSX
283  typelib_TypeClass_HYPER, &subsp,
284 #endif
285  reinterpret_cast<unsigned long>(arguments[i]), stack, &sp,
286  gpr, &ngpr);
287  TYPELIB_DANGER_RELEASE(ptd);
288  }
289  }
290  }
291  try {
292  try {
294  (*thisPtr)[slot.index], gpr, fpr, stack, sp, ret);
295  } catch (css::uno::Exception &) {
296  throw;
297  } catch (std::exception & e) {
298  throw css::uno::RuntimeException(
299  "C++ code threw "
300  + OStringToOUString(typeid(e).name(), RTL_TEXTENCODING_UTF8)
301  + ": " + OStringToOUString(e.what(), RTL_TEXTENCODING_UTF8));
302  } catch (...) {
303  throw css::uno::RuntimeException(
304  "C++ code threw unknown exception");
305  }
306  } catch (css::uno::Exception &) {
308  __cxxabiv1::__cxa_get_globals())->caughtExceptions;
309 #if !defined MACOSX && defined _LIBCPPABI_VERSION // detect libc++abi
310  // Very bad HACK to find out whether we run against a libcxxabi that has a new
311  // __cxa_exception::reserved member at the start, introduced with LLVM 10
312  // <https://github.com/llvm/llvm-project/commit/674ec1eb16678b8addc02a4b0534ab383d22fa77>
313  // "[libcxxabi] Insert padding in __cxa_exception struct for compatibility". The layout of
314  // the start of __cxa_exception is
315  //
316  // [8 byte void *reserve]
317  // 8 byte size_t referenceCount
318  //
319  // where the (bad, hacky) assumption is that reserve (if present) is null
320  // (__cxa_allocate_exception in at least LLVM 11 zero-fills the object, and nothing actively
321  // sets reserve) while referenceCount is non-null (__cxa_throw sets it to 1, and
322  // __cxa_decrement_exception_refcount destroys the exception as soon as it drops to 0; for a
323  // __cxa_dependent_exception, the referenceCount member is rather
324  //
325  // 8 byte void* primaryException
326  //
327  // but which also will always be set to a non-null value in
328  // __cxa_rethrow_primary_exception). As described in the definition of __cxa_exception
329  // (bridges/source/cpp_uno/gcc3_linux_aarch64/abi.hxx), this hack (together with the
330  // "#ifdef MACOSX" there) can be dropped once we can be sure that we only run against new
331  // libcxxabi that has the reserve member:
332  if (*reinterpret_cast<void **>(header) == nullptr) {
333  header = reinterpret_cast<__cxxabiv1::__cxa_exception*>(
334  reinterpret_cast<void **>(header) + 1);
335  }
336 #endif
338  header,
340  proxy->getBridge()->getCpp2Uno());
341  for (sal_Int32 i = 0; i != count; ++i) {
342  if (cppArgs[i] != nullptr) {
344  cppArgs[i], ptds[i],
345  reinterpret_cast<uno_ReleaseFunc>(css::uno::cpp_release));
346  TYPELIB_DANGER_RELEASE(ptds[i]);
347  }
348  }
349  TYPELIB_DANGER_RELEASE(rtd);
350  return;
351  }
352  *exception = nullptr;
353  for (sal_Int32 i = 0; i != count; ++i) {
354  if (cppArgs[i] != nullptr) {
355  if (parameters[i].bOut) {
356  if (parameters[i].bIn) {
357  uno_destructData(arguments[i], ptds[i], nullptr);
358  }
360  arguments[i], cppArgs[i], ptds[i],
361  proxy->getBridge()->getCpp2Uno());
362  }
364  cppArgs[i], ptds[i],
365  reinterpret_cast<uno_ReleaseFunc>(css::uno::cpp_release));
366  TYPELIB_DANGER_RELEASE(ptds[i]);
367  }
368  }
369  switch (retKind) {
371  switch (rtd->eTypeClass) {
372  case typelib_TypeClass_VOID:
373  break;
374  case typelib_TypeClass_BOOLEAN:
375  case typelib_TypeClass_BYTE:
376  case typelib_TypeClass_SHORT:
377  case typelib_TypeClass_UNSIGNED_SHORT:
378  case typelib_TypeClass_LONG:
379  case typelib_TypeClass_UNSIGNED_LONG:
380  case typelib_TypeClass_HYPER:
381  case typelib_TypeClass_UNSIGNED_HYPER:
382  case typelib_TypeClass_CHAR:
383  case typelib_TypeClass_ENUM:
384  case typelib_TypeClass_STRUCT:
385  std::memcpy(ret, gpr, rtd->nSize);
386  break;
387  case typelib_TypeClass_FLOAT:
388  case typelib_TypeClass_DOUBLE:
389  std::memcpy(ret, fpr, rtd->nSize);
390  break;
391  default:
392  assert(false);
393  }
394  break;
396  switch (rtd->nSize) {
397  case 16:
398  std::memcpy(static_cast<char *>(ret) + 12, fpr + 3, 4);
399  [[fallthrough]];
400  case 12:
401  std::memcpy(static_cast<char *>(ret) + 8, fpr + 2, 4);
402  [[fallthrough]];
403  case 8:
404  std::memcpy(static_cast<char *>(ret) + 4, fpr + 1, 4);
405  [[fallthrough]];
406  case 4:
407  std::memcpy(ret, fpr, 4);
408  break;
409  default:
410  assert(false);
411  }
412  break;
414  std::memcpy(ret, fpr, rtd->nSize);
415  break;
417  break;
418  }
419  if (retConv) {
421  returnValue, ret, rtd, proxy->getBridge()->getCpp2Uno());
423  ret, rtd, reinterpret_cast<uno_ReleaseFunc>(css::uno::cpp_release));
424  }
425  TYPELIB_DANGER_RELEASE(rtd);
426 }
427 
428 }
429 
430 namespace bridges::cpp_uno::shared {
431 
433  uno_Interface * pUnoI, typelib_TypeDescription const * pMemberDescr,
434  void * pReturn, void ** pArgs, uno_Any ** ppException)
435 {
436  UnoInterfaceProxy * proxy = static_cast<UnoInterfaceProxy *>(pUnoI);
437  switch (pMemberDescr->eTypeClass) {
438  case typelib_TypeClass_INTERFACE_ATTRIBUTE:
439  {
440  typelib_InterfaceAttributeTypeDescription const * atd
441  = reinterpret_cast<
442  typelib_InterfaceAttributeTypeDescription const *>(
443  pMemberDescr);
444  VtableSlot slot(getVtableSlot(atd));
445  if (pReturn != nullptr) { // getter
446  call(
447  proxy, slot, atd->pAttributeTypeRef, 0, nullptr, pReturn, pArgs,
448  ppException);
449  } else { // setter
450  typelib_MethodParameter param = {
451  nullptr, atd->pAttributeTypeRef, true, false };
452  typelib_TypeDescriptionReference * rtd = nullptr;
454  &rtd, typelib_TypeClass_VOID, OUString("void").pData);
455  slot.index += 1;
456  call(proxy, slot, rtd, 1, &param, pReturn, pArgs, ppException);
458  }
459  break;
460  }
461  case typelib_TypeClass_INTERFACE_METHOD:
462  {
463  typelib_InterfaceMethodTypeDescription const * mtd
464  = reinterpret_cast<
465  typelib_InterfaceMethodTypeDescription const *>(
466  pMemberDescr);
467  VtableSlot slot(getVtableSlot(mtd));
468  switch (slot.index) {
469  case 1:
470  pUnoI->acquire(pUnoI);
471  *ppException = nullptr;
472  break;
473  case 2:
474  pUnoI->release(pUnoI);
475  *ppException = nullptr;
476  break;
477  case 0:
478  {
479  typelib_TypeDescription * td = nullptr;
480  TYPELIB_DANGER_GET(
481  &td,
482  (static_cast<css::uno::Type *>(pArgs[0])
483  ->getTypeLibType()));
484  if (td != nullptr) {
485  uno_Interface * ifc = nullptr;
486  proxy->pBridge->getUnoEnv()->getRegisteredInterface(
487  proxy->pBridge->getUnoEnv(),
488  reinterpret_cast<void **>(&ifc), proxy->oid.pData,
489  reinterpret_cast<
490  typelib_InterfaceTypeDescription *>(td));
491  if (ifc != nullptr) {
493  static_cast<uno_Any *>(pReturn), &ifc, td,
494  nullptr);
495  ifc->release(ifc);
496  TYPELIB_DANGER_RELEASE(td);
497  *ppException = nullptr;
498  break;
499  }
500  TYPELIB_DANGER_RELEASE(td);
501  }
502  }
503  [[fallthrough]];
504  default:
505  call(
506  proxy, slot, mtd->pReturnTypeRef, mtd->nParams,
507  mtd->pParams, pReturn, pArgs, ppException);
508  break;
509  }
510  break;
511  }
512  default:
513  assert(false);
514  }
515 }
516 
517 }
518 
519 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void SAL_CALL uno_destructData(void *pValue, typelib_TypeDescription *pTypeDescr, uno_ReleaseFunc release) SAL_THROW_EXTERN_C()
std::unique_ptr< ContentProperties > pData
Represents a vtable slot of a C++ class.
Definition: vtables.hxx:59
std::type_info * __cxa_current_exception_type()
bool isSimpleType(typelib_TypeClass typeClass)
Determines whether a type is a "simple" type (VOID, BOOLEAN, BYTE, SHORT, UNSIGNED SHORT...
Definition: types.cxx:28
void SAL_CALL uno_any_construct(uno_Any *pDest, void *pSource, typelib_TypeDescription *pTypeDescr, uno_AcquireFunc acquire) SAL_THROW_EXTERN_C()
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 sal_Int8 header[]
uno_ExtEnvironment * getUnoEnv()
Definition: bridge.hxx:70
struct _uno_Any uno_Any
Definition: msvc/except.hxx:31
uno_Mapping * getUno2Cpp()
Definition: bridge.hxx:73
sal_Int32 offset
The offset of the vtable.
Definition: vtables.hxx:68
int i
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()
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()
__cxa_eh_globals * __cxa_get_globals()
void mapException(__cxxabiv1::__cxa_exception *exception, std::type_info const *type, uno_Any *any, uno_Mapping *mapping)
com::sun::star::uno::XInterface * getCppI()
ReturnKind getReturnKind(typelib_TypeDescription const *type)
void callVirtualFunction(unsigned long function, unsigned long *gpr, unsigned long *fpr, unsigned long *stack, sal_Int32 sp, void *ret)
char const * name