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#include <limits>
28#include <typeinfo>
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 <msvc/arm64.hxx>
44
45#include "abi.hxx"
46
47extern "C" IMAGE_DOS_HEADER const __ImageBase;
48
49extern "C" void vtableSlotCall();
50
51using namespace ::com::sun::star;
52
53namespace
54{
56 uno::TypeDescription const& description, typelib_TypeDescriptionReference* returnType,
57 sal_Int32 count, typelib_MethodParameter* parameters, sal_uInt64* gpr, sal_uInt64* fpr,
58 sal_uInt64* stack, void* indirectRet)
59{
61 if (returnType != 0)
62 TYPELIB_DANGER_GET(&rtd, returnType);
63
64 ReturnKind retKind = rtd == 0 ? RETURN_KIND_REG : getReturnKind(rtd);
65 bool retConv = rtd != 0 && bridges::cpp_uno::shared::relatesToInterfaceType(rtd);
66
67 void* retin = retKind == RETURN_KIND_INDIRECT && !retConv ? indirectRet
68 : rtd == 0 ? 0 : alloca(rtd->nSize);
69 void** args = static_cast<void**>(alloca(count * sizeof(void*)));
70 void** cppArgs = static_cast<void**>(alloca(count * sizeof(void*)));
72 = static_cast<typelib_TypeDescription**>(alloca(count * sizeof(typelib_TypeDescription*)));
73
74 sal_Int32 ngpr = 1;
75 sal_Int32 nfpr = 0;
76 sal_Int32 sp = 0;
77 for (sal_Int32 i = 0; i != count; ++i)
78 {
79 if (!parameters[i].bOut && bridges::cpp_uno::shared::isSimpleType(parameters[i].pTypeRef))
80 {
81 switch (parameters[i].pTypeRef->eTypeClass)
82 {
83 case typelib_TypeClass_BOOLEAN:
84 case typelib_TypeClass_BYTE:
85 case typelib_TypeClass_SHORT:
86 case typelib_TypeClass_UNSIGNED_SHORT:
87 case typelib_TypeClass_LONG:
88 case typelib_TypeClass_UNSIGNED_LONG:
89 case typelib_TypeClass_HYPER:
90 case typelib_TypeClass_UNSIGNED_HYPER:
91 case typelib_TypeClass_CHAR:
92 case typelib_TypeClass_ENUM:
93 args[i] = ngpr == 8 ? stack + sp++ : gpr + ngpr++;
94 break;
95 case typelib_TypeClass_FLOAT:
96 case typelib_TypeClass_DOUBLE:
97 args[i] = nfpr == 8 ? stack + sp++ : fpr + nfpr++;
98 break;
99 default:
100 assert(false);
101 }
102 argtds[i] = 0;
103 }
104 else
105 {
106 cppArgs[i] = reinterpret_cast<void*>(ngpr == 8 ? stack[sp++] : gpr[ngpr++]);
108 TYPELIB_DANGER_GET(&ptd, parameters[i].pTypeRef);
109 if (!parameters[i].bIn)
110 {
111 args[i] = alloca(ptd->nSize);
112 argtds[i] = ptd;
113 }
115 {
116 args[i] = alloca(ptd->nSize);
117 uno_copyAndConvertData(args[i], cppArgs[i], ptd, proxy->getBridge()->getCpp2Uno());
118 argtds[i] = ptd;
119 }
120 else
121 {
122 args[i] = cppArgs[i];
123 argtds[i] = 0;
124 TYPELIB_DANGER_RELEASE(ptd);
125 }
126 }
127 }
128
129 uno_Any exc;
130 uno_Any* pexc = &exc;
131 proxy->getUnoI()->pDispatcher(proxy->getUnoI(), description.get(), retin, args, &pexc);
132 if (pexc != 0)
133 {
134 for (sal_Int32 i = 0; i != count; ++i)
135 {
136 if (argtds[i] == 0)
137 continue;
138 if (parameters[i].bIn)
139 uno_destructData(args[i], argtds[i], 0);
140 TYPELIB_DANGER_RELEASE(argtds[i]);
141 }
142 if (rtd != 0)
143 TYPELIB_DANGER_RELEASE(rtd);
144 assert(pexc == &exc);
145 msvc_raiseException(&exc, proxy->getBridge()->getUno2Cpp());
146 }
147
148 for (sal_Int32 i = 0; i != count; ++i)
149 {
150 if (argtds[i] != 0)
151 {
152 if (parameters[i].bOut)
153 {
154 uno_destructData(cppArgs[i], argtds[i],
155 reinterpret_cast<uno_ReleaseFunc>(uno::cpp_release));
156 uno_copyAndConvertData(cppArgs[i], args[i], argtds[i],
157 proxy->getBridge()->getUno2Cpp());
158 }
159 uno_destructData(args[i], argtds[i], 0);
160 TYPELIB_DANGER_RELEASE(argtds[i]);
161 }
162 }
163
164 void* retout = 0; // avoid false -Werror=maybe-uninitialized
165 switch (retKind)
166 {
167 case RETURN_KIND_REG:
168 switch (rtd == 0 ? typelib_TypeClass_VOID : rtd->eTypeClass)
169 {
170 case typelib_TypeClass_VOID:
171 break;
172 case typelib_TypeClass_BOOLEAN:
173 case typelib_TypeClass_BYTE:
174 case typelib_TypeClass_SHORT:
175 case typelib_TypeClass_UNSIGNED_SHORT:
176 case typelib_TypeClass_LONG:
177 case typelib_TypeClass_UNSIGNED_LONG:
178 case typelib_TypeClass_HYPER:
179 case typelib_TypeClass_UNSIGNED_HYPER:
180 case typelib_TypeClass_CHAR:
181 case typelib_TypeClass_ENUM:
182 std::memcpy(gpr, retin, rtd->nSize);
183 assert(!retConv);
184 break;
185 case typelib_TypeClass_FLOAT:
186 case typelib_TypeClass_DOUBLE:
187 std::memcpy(fpr, retin, rtd->nSize);
188 assert(!retConv);
189 break;
190 case typelib_TypeClass_STRUCT:
191 if (retConv)
192 {
193 retout = gpr;
194 }
195 else
196 {
197 std::memcpy(gpr, retin, rtd->nSize);
198 }
199 break;
200 default:
201 assert(false);
202 }
203 break;
205 assert(rtd != 0);
206 switch (rtd->nSize)
207 {
208 case 16:
209 std::memcpy(fpr + 3, static_cast<char*>(retin) + 12, 4);
210 [[fallthrough]];
211 case 12:
212 std::memcpy(fpr + 2, static_cast<char*>(retin) + 8, 4);
213 [[fallthrough]];
214 case 8:
215 std::memcpy(fpr + 1, static_cast<char*>(retin) + 4, 4);
216 [[fallthrough]];
217 case 4:
218 std::memcpy(fpr, retin, 4);
219 break;
220 default:
221 assert(false);
222 }
223 assert(!retConv);
224 break;
226 assert(rtd != 0);
227 std::memcpy(fpr, retin, rtd->nSize);
228 assert(!retConv);
229 break;
231 retout = indirectRet;
232 break;
233 }
234
235 if (retConv)
236 {
237 uno_copyAndConvertData(retout, retin, rtd, proxy->getBridge()->getUno2Cpp());
238 uno_destructData(retin, rtd, 0);
239 }
240
241 if (rtd != 0)
242 TYPELIB_DANGER_RELEASE(rtd);
243}
244
245extern "C" void vtableCall(sal_Int32 functionIndex, sal_Int32 vtableOffset, sal_uInt64* gpr,
246 sal_uInt64* fpr, sal_uInt64* stack, void* indirectRet)
247{
250 reinterpret_cast<char*>(gpr[0]) - vtableOffset);
251 typelib_InterfaceTypeDescription* pInterfaceTD = proxy->getTypeDescr();
252 assert(functionIndex < pInterfaceTD->nMapFunctionIndexToMemberIndex);
253 sal_Int32 nMemberPos = pInterfaceTD->pMapFunctionIndexToMemberIndex[functionIndex];
254 assert(nMemberPos < pInterfaceTD->nAllMembers);
255 uno::TypeDescription aMemberDescr(pInterfaceTD->ppAllMembers[nMemberPos]);
256
257 switch (aMemberDescr.get()->eTypeClass)
258 {
259 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
260 {
261 typelib_TypeDescriptionReference* pAttrTypeRef
262 = reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(aMemberDescr.get())
263 ->pAttributeTypeRef;
264
265 if (pInterfaceTD->pMapMemberIndexToFunctionIndex[nMemberPos] == functionIndex)
266 {
267 // Getter:
268 call(proxy, aMemberDescr, pAttrTypeRef, 0, 0, gpr, fpr, stack, indirectRet);
269 }
270 else
271 {
272 // Setter:
273 typelib_MethodParameter param = { 0, pAttrTypeRef, true, false };
274 call(proxy, aMemberDescr, 0, 1, &param, gpr, fpr, stack, indirectRet);
275 }
276 }
277 break;
278 case typelib_TypeClass_INTERFACE_METHOD:
279 switch (functionIndex)
280 {
281 case 1:
282 proxy->acquireProxy();
283 break;
284 case 2:
285 proxy->releaseProxy();
286 break;
287 case 0:
288 {
289 typelib_TypeDescription* td = nullptr;
290 TYPELIB_DANGER_GET(&td,
291 (reinterpret_cast<uno::Type*>(gpr[1])->getTypeLibType()));
292 if (td != 0 && td->eTypeClass == typelib_TypeClass_INTERFACE)
293 {
294 uno::XInterface* ifc = nullptr;
295 proxy->getBridge()->getCppEnv()->getRegisteredInterface(
296 proxy->getBridge()->getCppEnv(), reinterpret_cast<void**>(&ifc),
297 proxy->getOid().pData,
298 reinterpret_cast<typelib_InterfaceTypeDescription*>(td));
299 if (ifc != 0)
300 {
301 uno_any_construct(reinterpret_cast<uno_Any*>(indirectRet), &ifc, td,
302 reinterpret_cast<uno_AcquireFunc>(uno::cpp_acquire));
303 ifc->release();
304 TYPELIB_DANGER_RELEASE(td);
305 break;
306 }
307 TYPELIB_DANGER_RELEASE(td);
308 }
309 }
310 [[fallthrough]];
311 default:
312 typelib_InterfaceMethodTypeDescription* pMethodTD
313 = reinterpret_cast<typelib_InterfaceMethodTypeDescription*>(
314 aMemberDescr.get());
315 call(proxy, aMemberDescr, pMethodTD->pReturnTypeRef, pMethodTD->nParams,
316 pMethodTD->pParams, gpr, fpr, stack, indirectRet);
317 }
318 break;
319 default:
320 assert(false);
321 }
322}
323
324std::size_t const codeSnippetSize = 8 * 4;
325
326unsigned char* GenerateVTableSlotTrampoline(unsigned char* code, sal_Int32 functionIndex,
327 sal_Int32 vtableOffset)
328{
329 // movz x9, <low functionIndex>
330 reinterpret_cast<unsigned int*>(code)[0] = 0xD2800009 | ((functionIndex & 0xFFFF) << 5);
331 // movk x9, <high functionIndex>, LSL #16
332 reinterpret_cast<unsigned int*>(code)[1] = 0xF2A00009 | ((functionIndex >> 16) << 5);
333 // movz x10, <low vtableOffset>
334 reinterpret_cast<unsigned int*>(code)[2] = 0xD280000A | ((vtableOffset & 0xFFFF) << 5);
335 // movk x10, <high vtableOffset>, LSL #16
336 reinterpret_cast<unsigned int*>(code)[3] = 0xF2A0000A | ((vtableOffset >> 16) << 5);
337 // ldr x11, +2*4
338 reinterpret_cast<unsigned int*>(code)[4] = 0x5800004B;
339 // br x11
340 reinterpret_cast<unsigned int*>(code)[5] = 0xD61F0160;
341 reinterpret_cast<void**>(code)[3] = reinterpret_cast<void*>(&vtableSlotCall);
342 return code + codeSnippetSize;
343}
344}
345
347{
349{
350 void* fn;
351};
352
355{
356 return static_cast<Slot*>(block) + 1;
357}
358
359std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(sal_Int32 slotCount)
360{
361 return (slotCount + 1) * sizeof(Slot) + slotCount * codeSnippetSize;
362}
363
364static sal_uInt32 imageRelative(void const* p)
365{
366 assert(reinterpret_cast<sal_uIntPtr>(p) >= reinterpret_cast<sal_uIntPtr>(&__ImageBase)
367 && reinterpret_cast<sal_uIntPtr>(p) - reinterpret_cast<sal_uIntPtr>(&__ImageBase)
368 <= std::numeric_limits<sal_uInt32>::max());
369 return reinterpret_cast<sal_uIntPtr>(p) - reinterpret_cast<sal_uIntPtr>(&__ImageBase);
370}
371
372namespace
373{
374// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast
375// on such proxy objects not crash:
376struct ProxyRtti
377{
378};
379
380// The following vtable RTTI data is based on how the code at
381// <https://github.com/llvm/llvm-project/blob/main/clang/lib/CodeGen/MicrosoftCXXABI.cpp> computes
382// such data, and on how <https://devblogs.microsoft.com/oldnewthing/20041025-00/?p=37483>
383// "Accessing the current module’s HINSTANCE from a static library" obtians __ImageBase:
384
385struct RttiClassHierarchyDescriptor;
386
387#pragma warning(push)
388#pragma warning(disable : 4324) // "structure was padded due to alignment specifier"
389
390struct alignas(16) RttiBaseClassDescriptor
391{
392 sal_uInt32 n0 = imageRelative(&typeid(ProxyRtti));
393 sal_uInt32 n1 = 0;
394 sal_uInt32 n2 = 0;
395 sal_uInt32 n3 = 0xFFFFFFFF;
396 sal_uInt32 n4 = 0;
397 sal_uInt32 n5 = 0x40;
398 sal_uInt32 n6;
399 RttiBaseClassDescriptor(RttiClassHierarchyDescriptor const* chd)
401 {
402 }
403};
404
405struct alignas(4) RttiBaseClassArray
406{
407 sal_uInt32 n0;
408 sal_uInt32 n1 = 0;
409 RttiBaseClassArray(RttiBaseClassDescriptor const* bcd)
411 {
412 }
413};
414
415struct alignas(8) RttiClassHierarchyDescriptor
416{
417 sal_uInt32 n0 = 0;
418 sal_uInt32 n1 = 0;
419 sal_uInt32 n2 = 1;
420 sal_uInt32 n3;
421 RttiClassHierarchyDescriptor(RttiBaseClassArray const* bca)
423 {
424 }
425};
426
427struct alignas(16) RttiCompleteObjectLocator
428{
429 sal_uInt32 n0 = 1;
430 sal_uInt32 n1 = 0;
431 sal_uInt32 n2 = 0;
432 sal_uInt32 n3 = imageRelative(&typeid(ProxyRtti));
433 sal_uInt32 n4;
434 sal_uInt32 n5 = imageRelative(this);
435 RttiCompleteObjectLocator(RttiClassHierarchyDescriptor const* chd)
437 {
438 }
439};
440
441struct Rtti
442{
443 RttiBaseClassDescriptor bcd;
444 RttiBaseClassArray bca;
445 RttiClassHierarchyDescriptor chd;
446 RttiCompleteObjectLocator col;
447 Rtti()
448 : bcd(&chd)
449 , bca(&bcd)
450 , chd(&bca)
451 , col(&chd)
452 {
453 }
454};
455
456#pragma warning(pop)
457}
458
460bridges::cpp_uno::shared::VtableFactory::initializeBlock(void* block, sal_Int32 slotCount,
461 sal_Int32,
462 typelib_InterfaceTypeDescription*)
463{
464 static Rtti rtti;
465
466 Slot* slots = mapBlockToVtable(block);
467 slots[-1].fn = &rtti.col;
468 return slots + slotCount;
469}
470
471unsigned char* VtableFactory::addLocalFunctions(VtableFactory::Slot** slots, unsigned char* code,
472 typelib_InterfaceTypeDescription const* type,
473 sal_Int32 functionOffset, sal_Int32 functionCount,
474 sal_Int32 vtableOffset)
475{
476 (*slots) -= functionCount;
477 VtableFactory::Slot* s = *slots;
478 for (sal_Int32 i = 0; i != type->nMembers; ++i)
479 {
480 typelib_TypeDescription* td = nullptr;
481 TYPELIB_DANGER_GET(&td, type->ppMembers[i]);
482 assert(td != 0);
483 switch (td->eTypeClass)
484 {
485 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
486 {
487 typelib_InterfaceAttributeTypeDescription* atd
488 = reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(td);
489 // Getter:
490 (s++)->fn = code;
491 code = GenerateVTableSlotTrampoline(code, functionOffset++, vtableOffset);
492 // Setter:
493 if (!atd->bReadOnly)
494 {
495 (s++)->fn = code;
496 code = GenerateVTableSlotTrampoline(code, functionOffset++, vtableOffset);
497 }
498 break;
499 }
500 case typelib_TypeClass_INTERFACE_METHOD:
501 (s++)->fn = code;
502 code = GenerateVTableSlotTrampoline(code, functionOffset++, vtableOffset);
503 break;
504 default:
505 assert(false);
506 }
507 TYPELIB_DANGER_RELEASE(td);
508 }
509 return code;
510}
511
512void VtableFactory::flushCode(unsigned char const* begin, unsigned char const* end)
513{
514 FlushInstructionCache(GetCurrentProcess(), begin, end - begin);
515}
516
517} // namespace bridges::cpp_uno::shared
518
519/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void SAL_CALL uno_any_construct(uno_Any *pDest, void *pSource, typelib_TypeDescription *pTypeDescr, uno_AcquireFunc acquire) SAL_THROW_EXTERN_C()
uno_Mapping * getUno2Cpp()
Definition: bridge.hxx:73
uno_ExtEnvironment * getCppEnv()
Definition: bridge.hxx:69
uno_Mapping * getCpp2Uno()
Definition: bridge.hxx:72
A cpp proxy wrapping a uno interface.
static CppInterfaceProxy * castInterfaceToProxy(void *pInterface)
typelib_InterfaceTypeDescription * getTypeDescr()
static Slot * mapBlockToVtable(void *block)
Given a pointer to a block, turn it into a vtable pointer.
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 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...
static Slot * initializeBlock(void *block, sal_Int32 slotCount, sal_Int32 vtableNumber, typelib_InterfaceTypeDescription *type)
Initialize a raw vtable block.
static std::size_t getBlockSize(sal_Int32 slotCount)
Calculate the size of a raw vtable block.
void SAL_CALL uno_destructData(void *pValue, typelib_TypeDescription *pTypeDescr, uno_ReleaseFunc release) SAL_THROW_EXTERN_C()
void SAL_CALL uno_copyAndConvertData(void *pDest, void *pSource, typelib_TypeDescription *pTypeDescr, uno_Mapping *mapping) SAL_THROW_EXTERN_C()
void vtableCall(sal_Int32 functionIndex, sal_Int32 vtableOffset, unsigned long *gpr, unsigned long *fpr, unsigned long *stack, void *indirectRet)
const int codeSnippetSize
void * p
struct _typelib_TypeDescription typelib_TypeDescription
Definition: msvc/except.hxx:53
struct _uno_Any uno_Any
Definition: msvc/except.hxx:32
void msvc_raiseException(uno_Any *pUnoExc, uno_Mapping *pUno2Cpp)
@ RETURN_KIND_HFA_DOUBLE
@ RETURN_KIND_INDIRECT
@ RETURN_KIND_REG
@ RETURN_KIND_HFA_FLOAT
RttiClassHierarchyDescriptor chd
IMAGE_DOS_HEADER const __ImageBase
void vtableSlotCall()
sal_uInt32 n0
sal_uInt32 n4
sal_uInt32 n2
sal_uInt32 n5
RttiCompleteObjectLocator col
RttiBaseClassDescriptor bcd
RttiBaseClassArray bca
sal_uInt32 n6
sal_uInt32 n3
sal_uInt32 n1
ReturnKind getReturnKind(typelib_TypeDescription const *type)
static sal_uInt32 imageRelative(void const *p)
bool isSimpleType(typelib_TypeClass typeClass)
Determines whether a type is a "simple" type (VOID, BOOLEAN, BYTE, SHORT, UNSIGNED SHORT,...
Definition: types.cxx:28
bool relatesToInterfaceType(typelib_TypeDescription const *type)
Determines whether a type relates to an interface type (is itself an interface type,...
Definition: types.cxx:41
int i
args
sal_Unicode code
ResultType type