tdf#130857 qt weld: Support mail merge "Server Auth" dialog
[LibreOffice.git] / bridges / source / cpp_uno / gcc3_linux_aarch64 / cpp2uno.cxx
blob669c4443c5f02fad3864dfcc3ff96ce4e7145e00
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>
27 #include <typeinfo>
29 #include <dlfcn.h>
31 #include <com/sun/star/uno/XInterface.hpp>
32 #include <com/sun/star/uno/genfunc.hxx>
33 #include <sal/alloca.h>
34 #include <sal/types.h>
35 #include <typelib/typeclass.h>
36 #include <typelib/typedescription.h>
37 #include <typelib/typedescription.hxx>
39 #include <bridge.hxx>
40 #include <cppinterfaceproxy.hxx>
41 #include <types.hxx>
42 #include <vtablefactory.hxx>
44 #include "abi.hxx"
45 #include "vtablecall.hxx"
47 namespace {
49 void call(
50 bridges::cpp_uno::shared::CppInterfaceProxy * proxy,
51 css::uno::TypeDescription const & description,
52 typelib_TypeDescriptionReference * returnType, sal_Int32 count,
53 typelib_MethodParameter * parameters, unsigned long * gpr,
54 unsigned long * fpr, unsigned long * stack, void * indirectRet)
56 typelib_TypeDescription * rtd = nullptr;
57 if (returnType != nullptr) {
58 TYPELIB_DANGER_GET(&rtd, returnType);
60 abi_aarch64::ReturnKind retKind = rtd == nullptr
61 ? abi_aarch64::RETURN_KIND_REG : abi_aarch64::getReturnKind(rtd);
62 bool retConv = rtd != nullptr
63 && bridges::cpp_uno::shared::relatesToInterfaceType(rtd);
64 void * retin = retKind == abi_aarch64::RETURN_KIND_INDIRECT && !retConv
65 ? indirectRet : rtd == nullptr ? nullptr : alloca(rtd->nSize);
66 void ** args = static_cast< void ** >(alloca(count * sizeof (void *)));
67 void ** cppArgs = static_cast< void ** >(alloca(count * sizeof (void *)));
68 typelib_TypeDescription ** argtds = static_cast<typelib_TypeDescription **>(
69 alloca(count * sizeof (typelib_TypeDescription *)));
70 sal_Int32 ngpr = 1;
71 sal_Int32 nfpr = 0;
72 sal_Int32 sp = 0;
73 #ifdef MACOSX
74 sal_Int32 subsp = 0;
75 #endif
76 for (sal_Int32 i = 0; i != count; ++i) {
77 if (!parameters[i].bOut
78 && bridges::cpp_uno::shared::isSimpleType(parameters[i].pTypeRef))
80 switch (parameters[i].pTypeRef->eTypeClass) {
81 #ifdef MACOSX
82 case typelib_TypeClass_BOOLEAN:
83 case typelib_TypeClass_BYTE:
84 if (ngpr < 8)
86 args[i] = gpr + ngpr;
87 ngpr++;
89 else
91 args[i] = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(stack + sp) + subsp);
92 subsp += 1;
93 if (subsp == 8)
95 sp++;
96 subsp = 0;
99 break;
100 case typelib_TypeClass_SHORT:
101 case typelib_TypeClass_UNSIGNED_SHORT:
102 case typelib_TypeClass_CHAR:
103 if (ngpr < 8)
105 args[i] = gpr + ngpr;
106 ngpr++;
108 else
110 subsp = (subsp + 1) & ~0x1;
111 if (subsp == 8)
113 sp++;
114 subsp = 0;
116 args[i] = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(stack + sp) + subsp);
117 subsp += 2;
118 if (subsp == 8)
120 sp++;
121 subsp = 0;
124 break;
125 case typelib_TypeClass_LONG:
126 case typelib_TypeClass_UNSIGNED_LONG:
127 case typelib_TypeClass_ENUM:
128 if (ngpr < 8)
130 args[i] = gpr + ngpr;
131 ngpr++;
133 else
135 subsp = (subsp + 3) & ~0x3;
136 if (subsp == 8)
138 sp++;
139 subsp = 0;
141 args[i] = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(stack + sp) + subsp);
142 subsp += 4;
143 if (subsp == 8)
145 sp++;
146 subsp = 0;
149 break;
150 case typelib_TypeClass_HYPER:
151 case typelib_TypeClass_UNSIGNED_HYPER:
152 if (ngpr < 8)
154 args[i] = gpr + ngpr;
155 ngpr++;
157 else
159 if (subsp > 0)
161 sp++;
162 subsp = 0;
164 args[i] = stack + sp;
165 sp++;
167 break;
168 case typelib_TypeClass_FLOAT:
169 if (nfpr < 8)
171 args[i] = fpr + nfpr;
172 nfpr++;
174 else
176 subsp = (subsp + 3) & ~0x3;
177 if (subsp == 8)
179 sp++;
180 subsp = 0;
182 args[i] = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(stack + sp) + subsp);
183 subsp += 4;
184 if (subsp == 8)
186 sp++;
187 subsp = 0;
190 break;
191 case typelib_TypeClass_DOUBLE:
192 if (nfpr < 8)
194 args[i] = fpr + nfpr;
195 nfpr++;
197 else
199 if (subsp > 0)
201 sp++;
202 subsp = 0;
204 args[i] = stack + sp;
205 sp++;
207 break;
208 #else
209 case typelib_TypeClass_BOOLEAN:
210 case typelib_TypeClass_BYTE:
211 case typelib_TypeClass_SHORT:
212 case typelib_TypeClass_UNSIGNED_SHORT:
213 case typelib_TypeClass_LONG:
214 case typelib_TypeClass_UNSIGNED_LONG:
215 case typelib_TypeClass_HYPER:
216 case typelib_TypeClass_UNSIGNED_HYPER:
217 case typelib_TypeClass_CHAR:
218 case typelib_TypeClass_ENUM:
219 args[i] = ngpr == 8 ? stack + sp++ : gpr + ngpr++;
220 break;
221 case typelib_TypeClass_FLOAT:
222 case typelib_TypeClass_DOUBLE:
223 args[i] = nfpr == 8 ? stack + sp++ : fpr + nfpr++;
224 break;
225 #endif
226 default:
227 assert(false);
229 argtds[i] = nullptr;
230 } else {
231 #ifdef MACOSX
232 if (subsp > 0)
234 sp++;
235 subsp = 0;
237 #endif
238 cppArgs[i] = reinterpret_cast<void *>(
239 ngpr == 8 ? stack[sp++] : gpr[ngpr++]);
240 typelib_TypeDescription * ptd = nullptr;
241 TYPELIB_DANGER_GET(&ptd, parameters[i].pTypeRef);
242 if (!parameters[i].bIn) {
243 args[i] = alloca(ptd->nSize);
244 argtds[i] = ptd;
245 } else if (bridges::cpp_uno::shared::relatesToInterfaceType(ptd)) {
246 args[i] = alloca(ptd->nSize);
247 uno_copyAndConvertData(
248 args[i], cppArgs[i], ptd, proxy->getBridge()->getCpp2Uno());
249 argtds[i] = ptd;
250 } else {
251 args[i] = cppArgs[i];
252 argtds[i] = nullptr;
253 TYPELIB_DANGER_RELEASE(ptd);
257 uno_Any exc;
258 uno_Any * pexc = &exc;
259 proxy->getUnoI()->pDispatcher(
260 proxy->getUnoI(), description.get(), retin, args, &pexc);
261 if (pexc != nullptr) {
262 for (sal_Int32 i = 0; i != count; ++i) {
263 if (argtds[i] != nullptr) {
264 if (parameters[i].bIn) {
265 uno_destructData(args[i], argtds[i], nullptr);
267 TYPELIB_DANGER_RELEASE(argtds[i]);
270 if (rtd != nullptr) {
271 TYPELIB_DANGER_RELEASE(rtd);
273 abi_aarch64::raiseException(&exc, proxy->getBridge()->getUno2Cpp());
275 for (sal_Int32 i = 0; i != count; ++i) {
276 if (argtds[i] != nullptr) {
277 if (parameters[i].bOut) {
278 uno_destructData(
279 cppArgs[i], argtds[i],
280 reinterpret_cast<uno_ReleaseFunc>(css::uno::cpp_release));
281 uno_copyAndConvertData(
282 cppArgs[i], args[i], argtds[i],
283 proxy->getBridge()->getUno2Cpp());
285 uno_destructData(args[i], argtds[i], nullptr);
286 TYPELIB_DANGER_RELEASE(argtds[i]);
289 void * retout = nullptr; // avoid false -Werror=maybe-uninitialized
290 switch (retKind) {
291 case abi_aarch64::RETURN_KIND_REG:
292 switch (rtd == nullptr ? typelib_TypeClass_VOID : rtd->eTypeClass) {
293 case typelib_TypeClass_VOID:
294 break;
295 #if defined MACOSX
296 case typelib_TypeClass_BOOLEAN:
297 assert(rtd->nSize == sizeof (bool));
298 *gpr = static_cast<unsigned long>(*static_cast<bool *>(retin));
299 assert(!retConv);
300 break;
301 case typelib_TypeClass_BYTE:
302 assert(rtd->nSize == sizeof (sal_Int8));
303 *gpr = *static_cast<sal_Int8 *>(retin);
304 assert(!retConv);
305 break;
306 case typelib_TypeClass_SHORT:
307 assert(rtd->nSize == sizeof (sal_Int16));
308 *gpr = *static_cast<sal_Int16 *>(retin);
309 assert(!retConv);
310 break;
311 case typelib_TypeClass_UNSIGNED_SHORT:
312 assert(rtd->nSize == sizeof (sal_uInt16));
313 *gpr = *static_cast<sal_uInt16 *>(retin);
314 assert(!retConv);
315 break;
316 case typelib_TypeClass_CHAR:
317 assert(rtd->nSize == sizeof (sal_Unicode));
318 *gpr = *static_cast<sal_Unicode *>(retin);
319 assert(!retConv);
320 break;
321 #else
322 case typelib_TypeClass_BOOLEAN:
323 case typelib_TypeClass_BYTE:
324 case typelib_TypeClass_SHORT:
325 case typelib_TypeClass_UNSIGNED_SHORT:
326 case typelib_TypeClass_CHAR:
327 #endif
328 case typelib_TypeClass_LONG:
329 case typelib_TypeClass_UNSIGNED_LONG:
330 case typelib_TypeClass_HYPER:
331 case typelib_TypeClass_UNSIGNED_HYPER:
332 case typelib_TypeClass_ENUM:
333 std::memcpy(gpr, retin, rtd->nSize);
334 assert(!retConv);
335 break;
336 case typelib_TypeClass_FLOAT:
337 case typelib_TypeClass_DOUBLE:
338 std::memcpy(fpr, retin, rtd->nSize);
339 assert(!retConv);
340 break;
341 case typelib_TypeClass_STRUCT:
342 if (retConv) {
343 retout = gpr;
344 } else {
345 std::memcpy(gpr, retin, rtd->nSize);
347 break;
348 default:
349 assert(false);
351 break;
352 case abi_aarch64::RETURN_KIND_HFA_FLOAT:
353 assert(rtd != nullptr);
354 switch (rtd->nSize) {
355 case 16:
356 std::memcpy(fpr + 3, static_cast<char *>(retin) + 12, 4);
357 [[fallthrough]];
358 case 12:
359 std::memcpy(fpr + 2, static_cast<char *>(retin) + 8, 4);
360 [[fallthrough]];
361 case 8:
362 std::memcpy(fpr + 1, static_cast<char *>(retin) + 4, 4);
363 [[fallthrough]];
364 case 4:
365 std::memcpy(fpr, retin, 4);
366 break;
367 default:
368 assert(false);
370 assert(!retConv);
371 break;
372 case abi_aarch64::RETURN_KIND_HFA_DOUBLE:
373 assert(rtd != nullptr);
374 std::memcpy(fpr, retin, rtd->nSize);
375 assert(!retConv);
376 break;
377 case abi_aarch64::RETURN_KIND_INDIRECT:
378 retout = indirectRet;
379 break;
381 if (retConv) {
382 uno_copyAndConvertData(
383 retout, retin, rtd, proxy->getBridge()->getUno2Cpp());
384 uno_destructData(retin, rtd, nullptr);
386 if (rtd != nullptr) {
387 TYPELIB_DANGER_RELEASE(rtd);
393 void vtableCall(
394 sal_Int32 functionIndex, sal_Int32 vtableOffset,
395 unsigned long * gpr, unsigned long * fpr, unsigned long * stack,
396 void * indirectRet)
398 bridges::cpp_uno::shared::CppInterfaceProxy * proxy
399 = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
400 reinterpret_cast<char *>(gpr[0]) - vtableOffset);
401 typelib_InterfaceTypeDescription * type = proxy->getTypeDescr();
402 assert(functionIndex < type->nMapFunctionIndexToMemberIndex);
403 sal_Int32 pos = type->pMapFunctionIndexToMemberIndex[functionIndex];
404 css::uno::TypeDescription desc(type->ppAllMembers[pos]);
405 switch (desc.get()->eTypeClass) {
406 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
407 if (type->pMapMemberIndexToFunctionIndex[pos] == functionIndex) {
408 // Getter:
409 call(
410 proxy, desc,
411 reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>(
412 desc.get())->pAttributeTypeRef,
413 0, nullptr, gpr, fpr, stack, indirectRet);
414 } else {
415 // Setter:
416 typelib_MethodParameter param = {
417 nullptr,
418 reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>(
419 desc.get())->pAttributeTypeRef,
420 true, false };
421 call(proxy, desc, nullptr, 1, &param, gpr, fpr, stack, indirectRet);
423 break;
424 case typelib_TypeClass_INTERFACE_METHOD:
425 switch (functionIndex) {
426 case 1:
427 proxy->acquireProxy();
428 break;
429 case 2:
430 proxy->releaseProxy();
431 break;
432 case 0:
434 typelib_TypeDescription * td = nullptr;
435 TYPELIB_DANGER_GET(
436 &td,
437 (reinterpret_cast<css::uno::Type *>(gpr[1])
438 ->getTypeLibType()));
439 if (td != nullptr && td->eTypeClass == typelib_TypeClass_INTERFACE) {
440 css::uno::XInterface * ifc = nullptr;
441 proxy->getBridge()->getCppEnv()->getRegisteredInterface(
442 proxy->getBridge()->getCppEnv(),
443 reinterpret_cast<void **>(&ifc), proxy->getOid().pData,
444 reinterpret_cast<typelib_InterfaceTypeDescription *>(
445 td));
446 if (ifc != nullptr) {
447 uno_any_construct(
448 static_cast<uno_Any *>(indirectRet), &ifc, td,
449 reinterpret_cast<uno_AcquireFunc>(
450 css::uno::cpp_acquire));
451 ifc->release();
452 TYPELIB_DANGER_RELEASE(td);
453 break;
455 TYPELIB_DANGER_RELEASE(td);
458 [[fallthrough]];
459 default:
460 call(
461 proxy, desc,
462 reinterpret_cast<typelib_InterfaceMethodTypeDescription *>(
463 desc.get())->pReturnTypeRef,
464 reinterpret_cast<typelib_InterfaceMethodTypeDescription *>(
465 desc.get())->nParams,
466 reinterpret_cast<typelib_InterfaceMethodTypeDescription *>(
467 desc.get())->pParams,
468 gpr, fpr, stack, indirectRet);
470 break;
471 default:
472 assert(false);
476 namespace {
478 std::size_t const codeSnippetSize = 8 * 4;
480 unsigned char * generateCodeSnippet(
481 unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset)
483 // movz x9, <low functionIndex>
484 reinterpret_cast<unsigned int *>(code)[0] = 0xD2800009
485 | ((functionIndex & 0xFFFF) << 5);
486 // movk x9, <high functionIndex>, LSL #16
487 reinterpret_cast<unsigned int *>(code)[1] = 0xF2A00009
488 | ((functionIndex >> 16) << 5);
489 // movz x10, <low vtableOffset>
490 reinterpret_cast<unsigned int *>(code)[2] = 0xD280000A
491 | ((vtableOffset & 0xFFFF) << 5);
492 // movk x10, <high vtableOffset>, LSL #16
493 reinterpret_cast<unsigned int *>(code)[3] = 0xF2A0000A
494 | ((vtableOffset >> 16) << 5);
495 // ldr x11, +2*4
496 reinterpret_cast<unsigned int *>(code)[4] = 0x5800004B;
497 // br x11
498 reinterpret_cast<unsigned int *>(code)[5] = 0xD61F0160;
499 reinterpret_cast<unsigned long *>(code)[3]
500 = reinterpret_cast<unsigned long>(&vtableSlotCall);
501 return code + codeSnippetSize;
506 struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; };
508 bridges::cpp_uno::shared::VtableFactory::Slot *
509 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) {
510 return static_cast<Slot *>(block) + 2;
513 std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(
514 sal_Int32 slotCount)
516 return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
519 namespace {
520 // Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast
521 // on such proxy objects not crash:
522 struct ProxyRtti {};
525 bridges::cpp_uno::shared::VtableFactory::Slot *
526 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
527 void * block, sal_Int32 slotCount, sal_Int32,
528 typelib_InterfaceTypeDescription *)
530 Slot * slots = mapBlockToVtable(block);
531 slots[-2].fn = nullptr;
532 slots[-1].fn = &typeid(ProxyRtti);
533 return slots + slotCount;
536 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
537 Slot ** slots, unsigned char * code,
538 #ifdef USE_DOUBLE_MMAP
539 sal_PtrDiff writetoexecdiff,
540 #endif
541 typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
542 sal_Int32 functionCount, sal_Int32 vtableOffset)
544 #ifndef USE_DOUBLE_MMAP
545 constexpr sal_PtrDiff writetoexecdiff = 0;
546 #endif
547 (*slots) -= functionCount;
548 Slot * s = *slots;
549 for (sal_Int32 i = 0; i != type->nMembers; ++i) {
550 typelib_TypeDescription * td = nullptr;
551 TYPELIB_DANGER_GET(&td, type->ppMembers[i]);
552 assert(td != nullptr);
553 switch (td->eTypeClass) {
554 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
556 typelib_InterfaceAttributeTypeDescription * atd
557 = reinterpret_cast<
558 typelib_InterfaceAttributeTypeDescription *>(td);
559 // Getter:
560 (s++)->fn = code + writetoexecdiff;
561 code = generateCodeSnippet(
562 code, functionOffset++, vtableOffset);
563 // Setter:
564 if (!atd->bReadOnly) {
565 (s++)->fn = code + writetoexecdiff;
566 code = generateCodeSnippet(
567 code, functionOffset++, vtableOffset);
569 break;
571 case typelib_TypeClass_INTERFACE_METHOD:
572 (s++)->fn = code + writetoexecdiff;
573 code = generateCodeSnippet(code, functionOffset++, vtableOffset);
574 break;
575 default:
576 assert(false);
578 TYPELIB_DANGER_RELEASE(td);
580 return code;
583 void bridges::cpp_uno::shared::VtableFactory::flushCode(
584 unsigned char const * begin, unsigned char const * end)
586 #if !defined ANDROID && !defined MACOSX
587 static void (*clear_cache)(unsigned char const *, unsigned char const *)
588 = (void (*)(unsigned char const *, unsigned char const *)) dlsym(
589 RTLD_DEFAULT, "__clear_cache");
590 (*clear_cache)(begin, end);
591 #else
592 // GCC clarified with
593 // <http://gcc.gnu.org/git/?p=gcc.git;a=commit;h=a90b0cdd444f6dde1084a439862cf507f6d3b2ae>
594 // "extend.texi (__clear_cache): Correct signature" that __builtin___clear_cache takes void*
595 // parameters, while Clang uses char* ever since
596 // <https://github.com/llvm/llvm-project/commit/c491a8d4577052bc6b3b4c72a7db6a7cfcbc2ed0> "Add
597 // support for __builtin___clear_cache in Clang" (TODO: see
598 // <https://bugs.llvm.org/show_bug.cgi?id=48489> "__builtin___clear_cache() has a different
599 // prototype than GCC"; once fixed for our Clang baseline, we can drop the reinterpret_casts):
600 __builtin___clear_cache(
601 reinterpret_cast<char *>(const_cast<unsigned char *>(begin)),
602 reinterpret_cast<char *>(const_cast<unsigned char *>(end)));
603 #endif
606 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */