nss: upgrade to release 3.73
[LibreOffice.git] / bridges / source / cpp_uno / msvc_win32_arm64 / cpp2uno.cxx
blobcfefa60e748a366774c0eb874c2c31b02b98f5fc
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
22 #include <cassert>
23 #include <cstdarg>
24 #include <cstddef>
25 #include <cstdlib>
26 #include <cstring>
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>
36 #include <bridge.hxx>
37 #include <cppinterfaceproxy.hxx>
38 #include <types.hxx>
39 #include <vtablefactory.hxx>
41 #include <msvc/arm64.hxx>
43 #include "abi.hxx"
45 extern "C" void vtableSlotCall();
47 using namespace ::com::sun::star;
49 namespace
51 void call(bridges::cpp_uno::shared::CppInterfaceProxy* proxy,
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)
56 typelib_TypeDescription* rtd = 0;
57 if (returnType != 0)
58 TYPELIB_DANGER_GET(&rtd, returnType);
60 ReturnKind retKind = rtd == 0 ? RETURN_KIND_REG : getReturnKind(rtd);
61 bool retConv = rtd != 0 && bridges::cpp_uno::shared::relatesToInterfaceType(rtd);
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*)));
67 typelib_TypeDescription** argtds
68 = static_cast<typelib_TypeDescription**>(alloca(count * sizeof(typelib_TypeDescription*)));
70 sal_Int32 ngpr = 1;
71 sal_Int32 nfpr = 0;
72 sal_Int32 sp = 0;
73 for (sal_Int32 i = 0; i != count; ++i)
75 if (!parameters[i].bOut && bridges::cpp_uno::shared::isSimpleType(parameters[i].pTypeRef))
77 switch (parameters[i].pTypeRef->eTypeClass)
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);
98 argtds[i] = 0;
100 else
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)
107 args[i] = alloca(ptd->nSize);
108 argtds[i] = ptd;
110 else if (bridges::cpp_uno::shared::relatesToInterfaceType(ptd))
112 args[i] = alloca(ptd->nSize);
113 uno_copyAndConvertData(args[i], cppArgs[i], ptd, proxy->getBridge()->getCpp2Uno());
114 argtds[i] = ptd;
116 else
118 args[i] = cppArgs[i];
119 argtds[i] = 0;
120 TYPELIB_DANGER_RELEASE(ptd);
125 uno_Any exc;
126 uno_Any* pexc = &exc;
127 proxy->getUnoI()->pDispatcher(proxy->getUnoI(), description.get(), retin, args, &pexc);
128 if (pexc != 0)
130 for (sal_Int32 i = 0; i != count; ++i)
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]);
138 if (rtd != 0)
139 TYPELIB_DANGER_RELEASE(rtd);
140 assert(pexc == &exc);
141 msvc_raiseException(&exc, proxy->getBridge()->getUno2Cpp());
144 for (sal_Int32 i = 0; i != count; ++i)
146 if (argtds[i] != 0)
148 if (parameters[i].bOut)
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());
155 uno_destructData(args[i], argtds[i], 0);
156 TYPELIB_DANGER_RELEASE(argtds[i]);
160 void* retout = 0; // avoid false -Werror=maybe-uninitialized
161 switch (retKind)
163 case RETURN_KIND_REG:
164 switch (rtd == 0 ? typelib_TypeClass_VOID : rtd->eTypeClass)
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)
189 retout = gpr;
191 else
193 std::memcpy(gpr, retin, rtd->nSize);
195 break;
196 default:
197 assert(false);
199 break;
200 case RETURN_KIND_HFA_FLOAT:
201 assert(rtd != 0);
202 switch (rtd->nSize)
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);
219 assert(!retConv);
220 break;
221 case RETURN_KIND_HFA_DOUBLE:
222 assert(rtd != 0);
223 std::memcpy(fpr, retin, rtd->nSize);
224 assert(!retConv);
225 break;
226 case RETURN_KIND_INDIRECT:
227 retout = indirectRet;
228 break;
231 if (retConv)
233 uno_copyAndConvertData(retout, retin, rtd, proxy->getBridge()->getUno2Cpp());
234 uno_destructData(retin, rtd, 0);
237 if (rtd != 0)
238 TYPELIB_DANGER_RELEASE(rtd);
241 extern "C" void vtableCall(sal_Int32 functionIndex, sal_Int32 vtableOffset, sal_uInt64* gpr,
242 sal_uInt64* fpr, sal_uInt64* stack, void* indirectRet)
244 bridges::cpp_uno::shared::CppInterfaceProxy* proxy
245 = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
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]);
253 switch (aMemberDescr.get()->eTypeClass)
255 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
257 typelib_TypeDescriptionReference* pAttrTypeRef
258 = reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(aMemberDescr.get())
259 ->pAttributeTypeRef;
261 if (pInterfaceTD->pMapMemberIndexToFunctionIndex[nMemberPos] == functionIndex)
263 // Getter:
264 call(proxy, aMemberDescr, pAttrTypeRef, 0, 0, gpr, fpr, stack, indirectRet);
266 else
268 // Setter:
269 typelib_MethodParameter param = { 0, pAttrTypeRef, true, false };
270 call(proxy, aMemberDescr, 0, 1, &param, gpr, fpr, stack, indirectRet);
273 break;
274 case typelib_TypeClass_INTERFACE_METHOD:
275 switch (functionIndex)
277 case 1:
278 proxy->acquireProxy();
279 break;
280 case 2:
281 proxy->releaseProxy();
282 break;
283 case 0:
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)
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)
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;
303 TYPELIB_DANGER_RELEASE(td);
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);
314 break;
315 default:
316 assert(false);
320 std::size_t const codeSnippetSize = 8 * 4;
322 unsigned char* GenerateVTableSlotTrampoline(unsigned char* code, sal_Int32 functionIndex,
323 sal_Int32 vtableOffset)
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;
342 namespace bridges::cpp_uno::shared
344 struct bridges::cpp_uno::shared::VtableFactory::Slot
346 void* fn;
349 bridges::cpp_uno::shared::VtableFactory::Slot*
350 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void* block)
352 return static_cast<Slot*>(block) + 1;
355 std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(sal_Int32 slotCount)
357 return (slotCount + 1) * sizeof(Slot) + slotCount * codeSnippetSize;
360 bridges::cpp_uno::shared::VtableFactory::Slot*
361 bridges::cpp_uno::shared::VtableFactory::initializeBlock(void* block, sal_Int32 slotCount,
362 sal_Int32,
363 typelib_InterfaceTypeDescription*)
365 struct Rtti
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"))
377 static Rtti rtti;
379 Slot* slots = mapBlockToVtable(block);
380 slots[-1].fn = &rtti;
381 return slots + slotCount;
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)
389 (*slots) -= functionCount;
390 VtableFactory::Slot* s = *slots;
391 for (sal_Int32 i = 0; i != type->nMembers; ++i)
393 typelib_TypeDescription* td = nullptr;
394 TYPELIB_DANGER_GET(&td, type->ppMembers[i]);
395 assert(td != 0);
396 switch (td->eTypeClass)
398 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
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)
408 (s++)->fn = code;
409 code = GenerateVTableSlotTrampoline(code, functionOffset++, vtableOffset);
411 break;
413 case typelib_TypeClass_INTERFACE_METHOD:
414 (s++)->fn = code;
415 code = GenerateVTableSlotTrampoline(code, functionOffset++, vtableOffset);
416 break;
417 default:
418 assert(false);
420 TYPELIB_DANGER_RELEASE(td);
422 return code;
425 void VtableFactory::flushCode(unsigned char const* begin, unsigned char const* end)
427 FlushInstructionCache(GetCurrentProcess(), begin, end - begin);
430 } // namespace bridges::cpp_uno::shared
432 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */