LibreOffice Module bridges (master)  1
gcc3_linux_aarch64/cpp2uno.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 <cstdarg>
24 #include <cstddef>
25 #include <cstdlib>
26 #include <cstring>
27 
28 #include <dlfcn.h>
29 
30 #include <com/sun/star/uno/XInterface.hpp>
31 #include <com/sun/star/uno/genfunc.hxx>
32 #include <sal/alloca.h>
33 #include <sal/types.h>
34 #include <typelib/typeclass.h>
35 #include <typelib/typedescription.h>
36 #include <typelib/typedescription.hxx>
37 
38 #include <bridge.hxx>
39 #include <cppinterfaceproxy.hxx>
40 #include <types.hxx>
41 #include <vtablefactory.hxx>
42 
43 #include "abi.hxx"
44 #include "vtablecall.hxx"
45 
46 namespace {
47 
48 void call(
50  css::uno::TypeDescription const & description,
51  typelib_TypeDescriptionReference * returnType, sal_Int32 count,
52  typelib_MethodParameter * parameters, unsigned long * gpr,
53  unsigned long * fpr, unsigned long * stack, void * indirectRet)
54 {
55  typelib_TypeDescription * rtd = nullptr;
56  if (returnType != nullptr) {
57  TYPELIB_DANGER_GET(&rtd, returnType);
58  }
59  abi_aarch64::ReturnKind retKind = rtd == nullptr
61  bool retConv = rtd != nullptr
63  void * retin = retKind == abi_aarch64::RETURN_KIND_INDIRECT && !retConv
64  ? indirectRet : rtd == nullptr ? nullptr : alloca(rtd->nSize);
65  void ** args = static_cast< void ** >(alloca(count * sizeof (void *)));
66  void ** cppArgs = static_cast< void ** >(alloca(count * sizeof (void *)));
67  typelib_TypeDescription ** argtds = static_cast<typelib_TypeDescription **>(
68  alloca(count * sizeof (typelib_TypeDescription *)));
69  sal_Int32 ngpr = 1;
70  sal_Int32 nfpr = 0;
71  sal_Int32 sp = 0;
72 #ifdef MACOSX
73  sal_Int32 subsp = 0;
74 #endif
75  for (sal_Int32 i = 0; i != count; ++i) {
76  if (!parameters[i].bOut
77  && bridges::cpp_uno::shared::isSimpleType(parameters[i].pTypeRef))
78  {
79  switch (parameters[i].pTypeRef->eTypeClass) {
80 #ifdef MACOSX
81  case typelib_TypeClass_BOOLEAN:
82  case typelib_TypeClass_BYTE:
83  if (ngpr < 8)
84  {
85  args[i] = gpr + ngpr;
86  ngpr++;
87  }
88  else
89  {
90  args[i] = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(stack + sp) + subsp);
91  subsp += 1;
92  if (subsp == 8)
93  {
94  sp++;
95  subsp = 0;
96  }
97  }
98  break;
99  case typelib_TypeClass_SHORT:
100  case typelib_TypeClass_UNSIGNED_SHORT:
101  case typelib_TypeClass_CHAR:
102  if (ngpr < 8)
103  {
104  args[i] = gpr + ngpr;
105  ngpr++;
106  }
107  else
108  {
109  subsp = (subsp + 1) & ~0x1;
110  if (subsp == 8)
111  {
112  sp++;
113  subsp = 0;
114  }
115  args[i] = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(stack + sp) + subsp);
116  subsp += 2;
117  if (subsp == 8)
118  {
119  sp++;
120  subsp = 0;
121  }
122  }
123  break;
124  case typelib_TypeClass_LONG:
125  case typelib_TypeClass_UNSIGNED_LONG:
126  case typelib_TypeClass_ENUM:
127  if (ngpr < 8)
128  {
129  args[i] = gpr + ngpr;
130  ngpr++;
131  }
132  else
133  {
134  subsp = (subsp + 3) & ~0x3;
135  if (subsp == 8)
136  {
137  sp++;
138  subsp = 0;
139  }
140  args[i] = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(stack + sp) + subsp);
141  subsp += 4;
142  if (subsp == 8)
143  {
144  sp++;
145  subsp = 0;
146  }
147  }
148  break;
149  case typelib_TypeClass_HYPER:
150  case typelib_TypeClass_UNSIGNED_HYPER:
151  if (ngpr < 8)
152  {
153  args[i] = gpr + ngpr;
154  ngpr++;
155  }
156  else
157  {
158  if (subsp > 0)
159  {
160  sp++;
161  subsp = 0;
162  }
163  args[i] = stack + sp;
164  sp++;
165  }
166  break;
167  case typelib_TypeClass_FLOAT:
168  if (nfpr < 8)
169  {
170  args[i] = fpr + nfpr;
171  nfpr++;
172  }
173  else
174  {
175  subsp = (subsp + 3) & ~0x3;
176  if (subsp == 8)
177  {
178  sp++;
179  subsp = 0;
180  }
181  args[i] = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(stack + sp) + subsp);
182  subsp += 4;
183  if (subsp == 8)
184  {
185  sp++;
186  subsp = 0;
187  }
188  }
189  break;
190  case typelib_TypeClass_DOUBLE:
191  if (nfpr < 8)
192  {
193  args[i] = fpr + nfpr;
194  nfpr++;
195  }
196  else
197  {
198  if (subsp > 0)
199  {
200  sp++;
201  subsp = 0;
202  }
203  args[i] = stack + sp;
204  sp++;
205  }
206  break;
207 #else
208  case typelib_TypeClass_BOOLEAN:
209  case typelib_TypeClass_BYTE:
210  case typelib_TypeClass_SHORT:
211  case typelib_TypeClass_UNSIGNED_SHORT:
212  case typelib_TypeClass_LONG:
213  case typelib_TypeClass_UNSIGNED_LONG:
214  case typelib_TypeClass_HYPER:
215  case typelib_TypeClass_UNSIGNED_HYPER:
216  case typelib_TypeClass_CHAR:
217  case typelib_TypeClass_ENUM:
218  args[i] = ngpr == 8 ? stack + sp++ : gpr + ngpr++;
219  break;
220  case typelib_TypeClass_FLOAT:
221  case typelib_TypeClass_DOUBLE:
222  args[i] = nfpr == 8 ? stack + sp++ : fpr + nfpr++;
223  break;
224 #endif
225  default:
226  assert(false);
227  }
228  argtds[i] = nullptr;
229  } else {
230 #ifdef MACOSX
231  if (subsp > 0)
232  {
233  sp++;
234  subsp = 0;
235  }
236 #endif
237  cppArgs[i] = reinterpret_cast<void *>(
238  ngpr == 8 ? stack[sp++] : gpr[ngpr++]);
239  typelib_TypeDescription * ptd = nullptr;
240  TYPELIB_DANGER_GET(&ptd, parameters[i].pTypeRef);
241  if (!parameters[i].bIn) {
242  args[i] = alloca(ptd->nSize);
243  argtds[i] = ptd;
245  args[i] = alloca(ptd->nSize);
247  args[i], cppArgs[i], ptd, proxy->getBridge()->getCpp2Uno());
248  argtds[i] = ptd;
249  } else {
250  args[i] = cppArgs[i];
251  argtds[i] = nullptr;
252  TYPELIB_DANGER_RELEASE(ptd);
253  }
254  }
255  }
256  uno_Any exc;
257  uno_Any * pexc = &exc;
258  proxy->getUnoI()->pDispatcher(
259  proxy->getUnoI(), description.get(), retin, args, &pexc);
260  if (pexc != nullptr) {
261  for (sal_Int32 i = 0; i != count; ++i) {
262  if (argtds[i] != nullptr) {
263  if (parameters[i].bIn) {
264  uno_destructData(args[i], argtds[i], nullptr);
265  }
266  TYPELIB_DANGER_RELEASE(argtds[i]);
267  }
268  }
269  if (rtd != nullptr) {
270  TYPELIB_DANGER_RELEASE(rtd);
271  }
273  }
274  for (sal_Int32 i = 0; i != count; ++i) {
275  if (argtds[i] != nullptr) {
276  if (parameters[i].bOut) {
278  cppArgs[i], argtds[i],
279  reinterpret_cast<uno_ReleaseFunc>(css::uno::cpp_release));
281  cppArgs[i], args[i], argtds[i],
282  proxy->getBridge()->getUno2Cpp());
283  }
284  uno_destructData(args[i], argtds[i], nullptr);
285  TYPELIB_DANGER_RELEASE(argtds[i]);
286  }
287  }
288  void * retout = nullptr; // avoid false -Werror=maybe-uninitialized
289  switch (retKind) {
291  switch (rtd == nullptr ? typelib_TypeClass_VOID : rtd->eTypeClass) {
292  case typelib_TypeClass_VOID:
293  break;
294 #if defined MACOSX
295  case typelib_TypeClass_BOOLEAN:
296  assert(rtd->nSize == sizeof (bool));
297  *gpr = static_cast<unsigned long>(*static_cast<bool *>(retin));
298  assert(!retConv);
299  break;
300  case typelib_TypeClass_BYTE:
301  assert(rtd->nSize == sizeof (sal_Int8));
302  *gpr = *static_cast<sal_Int8 *>(retin);
303  assert(!retConv);
304  break;
305  case typelib_TypeClass_SHORT:
306  assert(rtd->nSize == sizeof (sal_Int16));
307  *gpr = *static_cast<sal_Int16 *>(retin);
308  assert(!retConv);
309  break;
310  case typelib_TypeClass_UNSIGNED_SHORT:
311  assert(rtd->nSize == sizeof (sal_uInt16));
312  *gpr = *static_cast<sal_uInt16 *>(retin);
313  assert(!retConv);
314  break;
315  case typelib_TypeClass_CHAR:
316  assert(rtd->nSize == sizeof (sal_Unicode));
317  *gpr = *static_cast<sal_Unicode *>(retin);
318  assert(!retConv);
319  break;
320 #else
321  case typelib_TypeClass_BOOLEAN:
322  case typelib_TypeClass_BYTE:
323  case typelib_TypeClass_SHORT:
324  case typelib_TypeClass_UNSIGNED_SHORT:
325  case typelib_TypeClass_CHAR:
326 #endif
327  case typelib_TypeClass_LONG:
328  case typelib_TypeClass_UNSIGNED_LONG:
329  case typelib_TypeClass_HYPER:
330  case typelib_TypeClass_UNSIGNED_HYPER:
331  case typelib_TypeClass_ENUM:
332  std::memcpy(gpr, retin, rtd->nSize);
333  assert(!retConv);
334  break;
335  case typelib_TypeClass_FLOAT:
336  case typelib_TypeClass_DOUBLE:
337  std::memcpy(fpr, retin, rtd->nSize);
338  assert(!retConv);
339  break;
340  case typelib_TypeClass_STRUCT:
341  if (retConv) {
342  retout = gpr;
343  } else {
344  std::memcpy(gpr, retin, rtd->nSize);
345  }
346  break;
347  default:
348  assert(false);
349  }
350  break;
352  assert(rtd != nullptr);
353  switch (rtd->nSize) {
354  case 16:
355  std::memcpy(fpr + 3, static_cast<char *>(retin) + 12, 4);
356  [[fallthrough]];
357  case 12:
358  std::memcpy(fpr + 2, static_cast<char *>(retin) + 8, 4);
359  [[fallthrough]];
360  case 8:
361  std::memcpy(fpr + 1, static_cast<char *>(retin) + 4, 4);
362  [[fallthrough]];
363  case 4:
364  std::memcpy(fpr, retin, 4);
365  break;
366  default:
367  assert(false);
368  }
369  assert(!retConv);
370  break;
372  assert(rtd != nullptr);
373  std::memcpy(fpr, retin, rtd->nSize);
374  assert(!retConv);
375  break;
377  retout = indirectRet;
378  break;
379  }
380  if (retConv) {
382  retout, retin, rtd, proxy->getBridge()->getUno2Cpp());
383  uno_destructData(retin, rtd, nullptr);
384  }
385  if (rtd != nullptr) {
386  TYPELIB_DANGER_RELEASE(rtd);
387  }
388 }
389 
390 }
391 
393  sal_Int32 functionIndex, sal_Int32 vtableOffset,
394  unsigned long * gpr, unsigned long * fpr, unsigned long * stack,
395  void * indirectRet)
396 {
399  reinterpret_cast<char *>(gpr[0]) - vtableOffset);
400  typelib_InterfaceTypeDescription * type = proxy->getTypeDescr();
401  assert(functionIndex < type->nMapFunctionIndexToMemberIndex);
402  sal_Int32 pos = type->pMapFunctionIndexToMemberIndex[functionIndex];
403  css::uno::TypeDescription desc(type->ppAllMembers[pos]);
404  switch (desc.get()->eTypeClass) {
405  case typelib_TypeClass_INTERFACE_ATTRIBUTE:
406  if (type->pMapMemberIndexToFunctionIndex[pos] == functionIndex) {
407  // Getter:
408  call(
409  proxy, desc,
410  reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>(
411  desc.get())->pAttributeTypeRef,
412  0, nullptr, gpr, fpr, stack, indirectRet);
413  } else {
414  // Setter:
415  typelib_MethodParameter param = {
416  nullptr,
417  reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>(
418  desc.get())->pAttributeTypeRef,
419  true, false };
420  call(proxy, desc, nullptr, 1, &param, gpr, fpr, stack, indirectRet);
421  }
422  break;
423  case typelib_TypeClass_INTERFACE_METHOD:
424  switch (functionIndex) {
425  case 1:
426  proxy->acquireProxy();
427  break;
428  case 2:
429  proxy->releaseProxy();
430  break;
431  case 0:
432  {
433  typelib_TypeDescription * td = nullptr;
434  TYPELIB_DANGER_GET(
435  &td,
436  (reinterpret_cast<css::uno::Type *>(gpr[1])
437  ->getTypeLibType()));
438  if (td != nullptr && td->eTypeClass == typelib_TypeClass_INTERFACE) {
439  css::uno::XInterface * ifc = nullptr;
440  proxy->getBridge()->getCppEnv()->getRegisteredInterface(
441  proxy->getBridge()->getCppEnv(),
442  reinterpret_cast<void **>(&ifc), proxy->getOid().pData,
443  reinterpret_cast<typelib_InterfaceTypeDescription *>(
444  td));
445  if (ifc != nullptr) {
447  static_cast<uno_Any *>(indirectRet), &ifc, td,
448  reinterpret_cast<uno_AcquireFunc>(
449  css::uno::cpp_acquire));
450  ifc->release();
451  TYPELIB_DANGER_RELEASE(td);
452  break;
453  }
454  TYPELIB_DANGER_RELEASE(td);
455  }
456  }
457  [[fallthrough]];
458  default:
459  call(
460  proxy, desc,
461  reinterpret_cast<typelib_InterfaceMethodTypeDescription *>(
462  desc.get())->pReturnTypeRef,
463  reinterpret_cast<typelib_InterfaceMethodTypeDescription *>(
464  desc.get())->nParams,
465  reinterpret_cast<typelib_InterfaceMethodTypeDescription *>(
466  desc.get())->pParams,
467  gpr, fpr, stack, indirectRet);
468  }
469  break;
470  default:
471  assert(false);
472  }
473 }
474 
475 namespace {
476 
477 std::size_t const codeSnippetSize = 8 * 4;
478 
479 unsigned char * generateCodeSnippet(
480  unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset)
481 {
482  // movz x9, <low functionIndex>
483  reinterpret_cast<unsigned int *>(code)[0] = 0xD2800009
484  | ((functionIndex & 0xFFFF) << 5);
485  // movk x9, <high functionIndex>, LSL #16
486  reinterpret_cast<unsigned int *>(code)[1] = 0xF2A00009
487  | ((functionIndex >> 16) << 5);
488  // movz x10, <low vtableOffset>
489  reinterpret_cast<unsigned int *>(code)[2] = 0xD280000A
490  | ((vtableOffset & 0xFFFF) << 5);
491  // movk x10, <high vtableOffset>, LSL #16
492  reinterpret_cast<unsigned int *>(code)[3] = 0xF2A0000A
493  | ((vtableOffset >> 16) << 5);
494  // ldr x11, +2*4
495  reinterpret_cast<unsigned int *>(code)[4] = 0x5800004B;
496  // br x11
497  reinterpret_cast<unsigned int *>(code)[5] = 0xD61F0160;
498  reinterpret_cast<unsigned long *>(code)[3]
499  = reinterpret_cast<unsigned long>(&vtableSlotCall);
500  return code + codeSnippetSize;
501 }
502 
503 }
504 
506 
509  return static_cast<Slot *>(block) + 2;
510 }
511 
513  sal_Int32 slotCount)
514 {
515  return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
516 }
517 
520  void * block, sal_Int32 slotCount, sal_Int32,
521  typelib_InterfaceTypeDescription *)
522 {
523  Slot * slots = mapBlockToVtable(block);
524  slots[-2].fn = nullptr;
525  slots[-1].fn = nullptr;
526  return slots + slotCount;
527 }
528 
530  Slot ** slots, unsigned char * code,
531 #ifdef USE_DOUBLE_MMAP
532  sal_PtrDiff writetoexecdiff,
533 #endif
534  typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
535  sal_Int32 functionCount, sal_Int32 vtableOffset)
536 {
537 #ifndef USE_DOUBLE_MMAP
538  constexpr sal_PtrDiff writetoexecdiff = 0;
539 #endif
540  (*slots) -= functionCount;
541  Slot * s = *slots;
542  for (sal_Int32 i = 0; i != type->nMembers; ++i) {
543  typelib_TypeDescription * td = nullptr;
544  TYPELIB_DANGER_GET(&td, type->ppMembers[i]);
545  assert(td != nullptr);
546  switch (td->eTypeClass) {
547  case typelib_TypeClass_INTERFACE_ATTRIBUTE:
548  {
549  typelib_InterfaceAttributeTypeDescription * atd
550  = reinterpret_cast<
551  typelib_InterfaceAttributeTypeDescription *>(td);
552  // Getter:
553  (s++)->fn = code + writetoexecdiff;
554  code = generateCodeSnippet(
555  code, functionOffset++, vtableOffset);
556  // Setter:
557  if (!atd->bReadOnly) {
558  (s++)->fn = code + writetoexecdiff;
559  code = generateCodeSnippet(
560  code, functionOffset++, vtableOffset);
561  }
562  break;
563  }
564  case typelib_TypeClass_INTERFACE_METHOD:
565  (s++)->fn = code + writetoexecdiff;
566  code = generateCodeSnippet(code, functionOffset++, vtableOffset);
567  break;
568  default:
569  assert(false);
570  }
571  TYPELIB_DANGER_RELEASE(td);
572  }
573  return code;
574 }
575 
577  unsigned char const * begin, unsigned char const * end)
578 {
579 #if !defined ANDROID && !defined MACOSX
580  static void (*clear_cache)(unsigned char const *, unsigned char const *)
581  = (void (*)(unsigned char const *, unsigned char const *)) dlsym(
582  RTLD_DEFAULT, "__clear_cache");
583  (*clear_cache)(begin, end);
584 #else
585  // GCC clarified with
586  // <http://gcc.gnu.org/git/?p=gcc.git;a=commit;h=a90b0cdd444f6dde1084a439862cf507f6d3b2ae>
587  // "extend.texi (__clear_cache): Correct signature" that __builtin___clear_cache takes void*
588  // parameters, while Clang uses char* ever since
589  // <https://github.com/llvm/llvm-project/commit/c491a8d4577052bc6b3b4c72a7db6a7cfcbc2ed0> "Add
590  // support for __builtin___clear_cache in Clang" (TODO: see
591  // <https://bugs.llvm.org/show_bug.cgi?id=48489> "__builtin___clear_cache() has a different
592  // prototype than GCC"; once fixed for our Clang baseline, we can drop the reinterpret_casts):
593  __builtin___clear_cache(
594  reinterpret_cast<char *>(const_cast<unsigned char *>(begin)),
595  reinterpret_cast<char *>(const_cast<unsigned char *>(end)));
596 #endif
597 }
598 
599 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void vtableCall(sal_Int32 functionIndex, sal_Int32 vtableOffset, unsigned long *gpr, unsigned long *fpr, unsigned long *stack, void *indirectRet)
void SAL_CALL uno_destructData(void *pValue, typelib_TypeDescription *pTypeDescr, uno_ReleaseFunc release) SAL_THROW_EXTERN_C()
void raiseException(uno_Any *any, uno_Mapping *mapping)
signed char sal_Int8
tuple args
bool isSimpleType(typelib_TypeClass typeClass)
Determines whether a type is a "simple" type (VOID, BOOLEAN, BYTE, SHORT, UNSIGNED SHORT...
Definition: types.cxx:28
static std::size_t getBlockSize(sal_Int32 slotCount)
Calculate the size of a raw vtable block.
#define USE_DOUBLE_MMAP
sal_Unicode code
const int codeSnippetSize
void SAL_CALL uno_any_construct(uno_Any *pDest, void *pSource, typelib_TypeDescription *pTypeDescr, uno_AcquireFunc acquire) SAL_THROW_EXTERN_C()
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
sal_uInt16 sal_Unicode
enumrange< T >::Iterator begin(enumrange< T >)
size_t pos
static Slot * initializeBlock(void *block, sal_Int32 slotCount, sal_Int32 vtableNumber, typelib_InterfaceTypeDescription *type)
Initialize a raw vtable block.
static Slot * mapBlockToVtable(void *block)
Given a pointer to a block, turn it into a vtable pointer.
struct _uno_Any uno_Any
Definition: msvc/except.hxx:31
uno_Mapping * getUno2Cpp()
Definition: bridge.hxx:73
void vtableSlotCall()
uno_ExtEnvironment * getCppEnv()
Definition: bridge.hxx:69
static unsigned char * addLocalFunctions(Slot **slots, unsigned char *code, sal_PtrDiff writetoexecdiff, typelib_InterfaceTypeDescription const *type, sal_Int32 functionOffset, sal_Int32 functionCount, sal_Int32 vtableOffset)
Fill the vtable slots corresponding to all local (i.e., not inherited) functions of a given interface...
typelib_InterfaceTypeDescription * getTypeDescr()
A cpp proxy wrapping a uno interface.
int i
void SAL_CALL uno_copyAndConvertData(void *pDest, void *pSource, typelib_TypeDescription *pTypeDescr, uno_Mapping *mapping) SAL_THROW_EXTERN_C()
struct _typelib_TypeDescription typelib_TypeDescription
Definition: msvc/except.hxx:52
uno_Mapping * getCpp2Uno()
Definition: bridge.hxx:72
enumrange< T >::Iterator end(enumrange< T >)
static void flushCode(unsigned char const *begin, unsigned char const *end)
Flush all the generated code snippets of a vtable, on platforms that require it.
ResultType type
static CppInterfaceProxy * castInterfaceToProxy(void *pInterface)
ReturnKind getReturnKind(typelib_TypeDescription const *type)
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo