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
45extern "C" void vtableSlotCall();
46
47using namespace ::com::sun::star;
48
49namespace
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{
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++]);
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
241extern "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
320std::size_t const codeSnippetSize = 8 * 4;
321
322unsigned 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
343{
345{
346 void* fn;
347};
348
351{
352 return static_cast<Slot*>(block) + 1;
353}
354
355std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(sal_Int32 slotCount)
356{
357 return (slotCount + 1) * sizeof(Slot) + slotCount * codeSnippetSize;
358}
359
361bridges::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
384unsigned 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
425void 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: */
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
int n2
int n1
struct _typelib_TypeDescription typelib_TypeDescription
Definition: msvc/except.hxx:52
struct _uno_Any uno_Any
Definition: msvc/except.hxx:31
void msvc_raiseException(uno_Any *pUnoExc, uno_Mapping *pUno2Cpp)
@ RETURN_KIND_HFA_DOUBLE
@ RETURN_KIND_INDIRECT
@ RETURN_KIND_REG
@ RETURN_KIND_HFA_FLOAT
void vtableSlotCall()
ReturnKind getReturnKind(typelib_TypeDescription const *type)
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
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
sal_Unicode code
ResultType type