LibreOffice Module bridges (master)  1
msvc_win32_arm64/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 <com/sun/star/uno/XInterface.hpp>
29 #include <com/sun/star/uno/genfunc.hxx>
30 #include <sal/alloca.h>
31 #include <sal/types.h>
32 #include <typelib/typeclass.h>
33 #include <typelib/typedescription.h>
34 #include <typelib/typedescription.hxx>
35 
36 #include <bridge.hxx>
37 #include <cppinterfaceproxy.hxx>
38 #include <types.hxx>
39 #include <vtablefactory.hxx>
40 
41 #include <msvc/arm64.hxx>
42 
43 #include "abi.hxx"
44 
45 extern "C" void vtableSlotCall();
46 
47 using namespace ::com::sun::star;
48 
49 namespace
50 {
52  uno::TypeDescription const& description, typelib_TypeDescriptionReference* returnType,
53  sal_Int32 count, typelib_MethodParameter* parameters, sal_uInt64* gpr, sal_uInt64* fpr,
54  sal_uInt64* stack, void* indirectRet)
55 {
56  typelib_TypeDescription* rtd = 0;
57  if (returnType != 0)
58  TYPELIB_DANGER_GET(&rtd, returnType);
59 
60  ReturnKind retKind = rtd == 0 ? RETURN_KIND_REG : getReturnKind(rtd);
61  bool retConv = rtd != 0 && bridges::cpp_uno::shared::relatesToInterfaceType(rtd);
62 
63  void* retin = retKind == RETURN_KIND_INDIRECT && !retConv ? indirectRet
64  : rtd == 0 ? 0 : alloca(rtd->nSize);
65  void** args = static_cast<void**>(alloca(count * sizeof(void*)));
66  void** cppArgs = static_cast<void**>(alloca(count * sizeof(void*)));
68  = static_cast<typelib_TypeDescription**>(alloca(count * sizeof(typelib_TypeDescription*)));
69 
70  sal_Int32 ngpr = 1;
71  sal_Int32 nfpr = 0;
72  sal_Int32 sp = 0;
73  for (sal_Int32 i = 0; i != count; ++i)
74  {
75  if (!parameters[i].bOut && bridges::cpp_uno::shared::isSimpleType(parameters[i].pTypeRef))
76  {
77  switch (parameters[i].pTypeRef->eTypeClass)
78  {
79  case typelib_TypeClass_BOOLEAN:
80  case typelib_TypeClass_BYTE:
81  case typelib_TypeClass_SHORT:
82  case typelib_TypeClass_UNSIGNED_SHORT:
83  case typelib_TypeClass_LONG:
84  case typelib_TypeClass_UNSIGNED_LONG:
85  case typelib_TypeClass_HYPER:
86  case typelib_TypeClass_UNSIGNED_HYPER:
87  case typelib_TypeClass_CHAR:
88  case typelib_TypeClass_ENUM:
89  args[i] = ngpr == 8 ? stack + sp++ : gpr + ngpr++;
90  break;
91  case typelib_TypeClass_FLOAT:
92  case typelib_TypeClass_DOUBLE:
93  args[i] = nfpr == 8 ? stack + sp++ : fpr + nfpr++;
94  break;
95  default:
96  assert(false);
97  }
98  argtds[i] = 0;
99  }
100  else
101  {
102  cppArgs[i] = reinterpret_cast<void*>(ngpr == 8 ? stack[sp++] : gpr[ngpr++]);
103  typelib_TypeDescription* ptd = 0;
104  TYPELIB_DANGER_GET(&ptd, parameters[i].pTypeRef);
105  if (!parameters[i].bIn)
106  {
107  args[i] = alloca(ptd->nSize);
108  argtds[i] = ptd;
109  }
111  {
112  args[i] = alloca(ptd->nSize);
113  uno_copyAndConvertData(args[i], cppArgs[i], ptd, proxy->getBridge()->getCpp2Uno());
114  argtds[i] = ptd;
115  }
116  else
117  {
118  args[i] = cppArgs[i];
119  argtds[i] = 0;
120  TYPELIB_DANGER_RELEASE(ptd);
121  }
122  }
123  }
124 
125  uno_Any exc;
126  uno_Any* pexc = &exc;
127  proxy->getUnoI()->pDispatcher(proxy->getUnoI(), description.get(), retin, args, &pexc);
128  if (pexc != 0)
129  {
130  for (sal_Int32 i = 0; i != count; ++i)
131  {
132  if (argtds[i] == 0)
133  continue;
134  if (parameters[i].bIn)
135  uno_destructData(args[i], argtds[i], 0);
136  TYPELIB_DANGER_RELEASE(argtds[i]);
137  }
138  if (rtd != 0)
139  TYPELIB_DANGER_RELEASE(rtd);
140  assert(pexc == &exc);
141  msvc_raiseException(&exc, proxy->getBridge()->getUno2Cpp());
142  }
143 
144  for (sal_Int32 i = 0; i != count; ++i)
145  {
146  if (argtds[i] != 0)
147  {
148  if (parameters[i].bOut)
149  {
150  uno_destructData(cppArgs[i], argtds[i],
151  reinterpret_cast<uno_ReleaseFunc>(uno::cpp_release));
152  uno_copyAndConvertData(cppArgs[i], args[i], argtds[i],
153  proxy->getBridge()->getUno2Cpp());
154  }
155  uno_destructData(args[i], argtds[i], 0);
156  TYPELIB_DANGER_RELEASE(argtds[i]);
157  }
158  }
159 
160  void* retout = 0; // avoid false -Werror=maybe-uninitialized
161  switch (retKind)
162  {
163  case RETURN_KIND_REG:
164  switch (rtd == 0 ? typelib_TypeClass_VOID : rtd->eTypeClass)
165  {
166  case typelib_TypeClass_VOID:
167  break;
168  case typelib_TypeClass_BOOLEAN:
169  case typelib_TypeClass_BYTE:
170  case typelib_TypeClass_SHORT:
171  case typelib_TypeClass_UNSIGNED_SHORT:
172  case typelib_TypeClass_LONG:
173  case typelib_TypeClass_UNSIGNED_LONG:
174  case typelib_TypeClass_HYPER:
175  case typelib_TypeClass_UNSIGNED_HYPER:
176  case typelib_TypeClass_CHAR:
177  case typelib_TypeClass_ENUM:
178  std::memcpy(gpr, retin, rtd->nSize);
179  assert(!retConv);
180  break;
181  case typelib_TypeClass_FLOAT:
182  case typelib_TypeClass_DOUBLE:
183  std::memcpy(fpr, retin, rtd->nSize);
184  assert(!retConv);
185  break;
186  case typelib_TypeClass_STRUCT:
187  if (retConv)
188  {
189  retout = gpr;
190  }
191  else
192  {
193  std::memcpy(gpr, retin, rtd->nSize);
194  }
195  break;
196  default:
197  assert(false);
198  }
199  break;
201  assert(rtd != 0);
202  switch (rtd->nSize)
203  {
204  case 16:
205  std::memcpy(fpr + 3, static_cast<char*>(retin) + 12, 4);
206  [[fallthrough]];
207  case 12:
208  std::memcpy(fpr + 2, static_cast<char*>(retin) + 8, 4);
209  [[fallthrough]];
210  case 8:
211  std::memcpy(fpr + 1, static_cast<char*>(retin) + 4, 4);
212  [[fallthrough]];
213  case 4:
214  std::memcpy(fpr, retin, 4);
215  break;
216  default:
217  assert(false);
218  }
219  assert(!retConv);
220  break;
222  assert(rtd != 0);
223  std::memcpy(fpr, retin, rtd->nSize);
224  assert(!retConv);
225  break;
227  retout = indirectRet;
228  break;
229  }
230 
231  if (retConv)
232  {
233  uno_copyAndConvertData(retout, retin, rtd, proxy->getBridge()->getUno2Cpp());
234  uno_destructData(retin, rtd, 0);
235  }
236 
237  if (rtd != 0)
238  TYPELIB_DANGER_RELEASE(rtd);
239 }
240 
241 extern "C" void vtableCall(sal_Int32 functionIndex, sal_Int32 vtableOffset, sal_uInt64* gpr,
242  sal_uInt64* fpr, sal_uInt64* stack, void* indirectRet)
243 {
246  reinterpret_cast<char*>(gpr[0]) - vtableOffset);
247  typelib_InterfaceTypeDescription* pInterfaceTD = proxy->getTypeDescr();
248  assert(functionIndex < pInterfaceTD->nMapFunctionIndexToMemberIndex);
249  sal_Int32 nMemberPos = pInterfaceTD->pMapFunctionIndexToMemberIndex[functionIndex];
250  assert(nMemberPos < pInterfaceTD->nAllMembers);
251  uno::TypeDescription aMemberDescr(pInterfaceTD->ppAllMembers[nMemberPos]);
252 
253  switch (aMemberDescr.get()->eTypeClass)
254  {
255  case typelib_TypeClass_INTERFACE_ATTRIBUTE:
256  {
257  typelib_TypeDescriptionReference* pAttrTypeRef
258  = reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(aMemberDescr.get())
259  ->pAttributeTypeRef;
260 
261  if (pInterfaceTD->pMapMemberIndexToFunctionIndex[nMemberPos] == functionIndex)
262  {
263  // Getter:
264  call(proxy, aMemberDescr, pAttrTypeRef, 0, 0, gpr, fpr, stack, indirectRet);
265  }
266  else
267  {
268  // Setter:
269  typelib_MethodParameter param = { 0, pAttrTypeRef, true, false };
270  call(proxy, aMemberDescr, 0, 1, &param, gpr, fpr, stack, indirectRet);
271  }
272  }
273  break;
274  case typelib_TypeClass_INTERFACE_METHOD:
275  switch (functionIndex)
276  {
277  case 1:
278  proxy->acquireProxy();
279  break;
280  case 2:
281  proxy->releaseProxy();
282  break;
283  case 0:
284  {
285  typelib_TypeDescription* td = nullptr;
286  TYPELIB_DANGER_GET(&td,
287  (reinterpret_cast<uno::Type*>(gpr[1])->getTypeLibType()));
288  if (td != 0 && td->eTypeClass == typelib_TypeClass_INTERFACE)
289  {
290  uno::XInterface* ifc = nullptr;
291  proxy->getBridge()->getCppEnv()->getRegisteredInterface(
292  proxy->getBridge()->getCppEnv(), reinterpret_cast<void**>(&ifc),
293  proxy->getOid().pData,
294  reinterpret_cast<typelib_InterfaceTypeDescription*>(td));
295  if (ifc != 0)
296  {
297  uno_any_construct(reinterpret_cast<uno_Any*>(indirectRet), &ifc, td,
298  reinterpret_cast<uno_AcquireFunc>(uno::cpp_acquire));
299  ifc->release();
300  TYPELIB_DANGER_RELEASE(td);
301  break;
302  }
303  TYPELIB_DANGER_RELEASE(td);
304  }
305  }
306  [[fallthrough]];
307  default:
308  typelib_InterfaceMethodTypeDescription* pMethodTD
309  = reinterpret_cast<typelib_InterfaceMethodTypeDescription*>(
310  aMemberDescr.get());
311  call(proxy, aMemberDescr, pMethodTD->pReturnTypeRef, pMethodTD->nParams,
312  pMethodTD->pParams, gpr, fpr, stack, indirectRet);
313  }
314  break;
315  default:
316  assert(false);
317  }
318 }
319 
320 std::size_t const codeSnippetSize = 8 * 4;
321 
322 unsigned char* GenerateVTableSlotTrampoline(unsigned char* code, sal_Int32 functionIndex,
323  sal_Int32 vtableOffset)
324 {
325  // movz x9, <low functionIndex>
326  reinterpret_cast<unsigned int*>(code)[0] = 0xD2800009 | ((functionIndex & 0xFFFF) << 5);
327  // movk x9, <high functionIndex>, LSL #16
328  reinterpret_cast<unsigned int*>(code)[1] = 0xF2A00009 | ((functionIndex >> 16) << 5);
329  // movz x10, <low vtableOffset>
330  reinterpret_cast<unsigned int*>(code)[2] = 0xD280000A | ((vtableOffset & 0xFFFF) << 5);
331  // movk x10, <high vtableOffset>, LSL #16
332  reinterpret_cast<unsigned int*>(code)[3] = 0xF2A0000A | ((vtableOffset >> 16) << 5);
333  // ldr x11, +2*4
334  reinterpret_cast<unsigned int*>(code)[4] = 0x5800004B;
335  // br x11
336  reinterpret_cast<unsigned int*>(code)[5] = 0xD61F0160;
337  reinterpret_cast<void**>(code)[3] = reinterpret_cast<void*>(&vtableSlotCall);
338  return code + codeSnippetSize;
339 }
340 }
341 
342 namespace bridges::cpp_uno::shared
343 {
345 {
346  void* fn;
347 };
348 
351 {
352  return static_cast<Slot*>(block) + 1;
353 }
354 
355 std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(sal_Int32 slotCount)
356 {
357  return (slotCount + 1) * sizeof(Slot) + slotCount * codeSnippetSize;
358 }
359 
361 bridges::cpp_uno::shared::VtableFactory::initializeBlock(void* block, sal_Int32 slotCount,
362  sal_Int32,
363  typelib_InterfaceTypeDescription*)
364 {
365  struct Rtti
366  {
367  sal_Int32 n0, n1, n2;
368  type_info* rtti;
369  Rtti()
370  : n0(0)
371  , n1(0)
372  , n2(0)
373  , rtti(RTTInfos::get("com.sun.star.uno.XInterface"))
374  {
375  }
376  };
377  static Rtti rtti;
378 
379  Slot* slots = mapBlockToVtable(block);
380  slots[-1].fn = &rtti;
381  return slots + slotCount;
382 }
383 
384 unsigned char* VtableFactory::addLocalFunctions(VtableFactory::Slot** slots, unsigned char* code,
385  typelib_InterfaceTypeDescription const* type,
386  sal_Int32 functionOffset, sal_Int32 functionCount,
387  sal_Int32 vtableOffset)
388 {
389  (*slots) -= functionCount;
390  VtableFactory::Slot* s = *slots;
391  for (sal_Int32 i = 0; i != type->nMembers; ++i)
392  {
393  typelib_TypeDescription* td = nullptr;
394  TYPELIB_DANGER_GET(&td, type->ppMembers[i]);
395  assert(td != 0);
396  switch (td->eTypeClass)
397  {
398  case typelib_TypeClass_INTERFACE_ATTRIBUTE:
399  {
400  typelib_InterfaceAttributeTypeDescription* atd
401  = reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(td);
402  // Getter:
403  (s++)->fn = code;
404  code = GenerateVTableSlotTrampoline(code, functionOffset++, vtableOffset);
405  // Setter:
406  if (!atd->bReadOnly)
407  {
408  (s++)->fn = code;
409  code = GenerateVTableSlotTrampoline(code, functionOffset++, vtableOffset);
410  }
411  break;
412  }
413  case typelib_TypeClass_INTERFACE_METHOD:
414  (s++)->fn = code;
415  code = GenerateVTableSlotTrampoline(code, functionOffset++, vtableOffset);
416  break;
417  default:
418  assert(false);
419  }
420  TYPELIB_DANGER_RELEASE(td);
421  }
422  return code;
423 }
424 
425 void VtableFactory::flushCode(unsigned char const* begin, unsigned char const* end)
426 {
427  FlushInstructionCache(GetCurrentProcess(), begin, end - begin);
428 }
429 
430 } // namespace bridges::cpp_uno::shared
431 
432 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
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()
int n1
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.
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
int n2
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 msvc_raiseException(uno_Any *pUnoExc, uno_Mapping *pUno2Cpp)
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
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.
static CppInterfaceProxy * castInterfaceToProxy(void *pInterface)
ReturnKind getReturnKind(typelib_TypeDescription const *type)
void vtableSlotCall()