LibreOffice Module bridges (master) 1
gcc3_linux_aarch64/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 <typeinfo>
28
29#include <dlfcn.h>
30
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>
38
39#include <bridge.hxx>
40#include <cppinterfaceproxy.hxx>
41#include <types.hxx>
42#include <vtablefactory.hxx>
43
44#include "abi.hxx"
45#include "vtablecall.hxx"
46
47namespace {
48
49void call(
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)
55{
56 typelib_TypeDescription * rtd = nullptr;
57 if (returnType != nullptr) {
58 TYPELIB_DANGER_GET(&rtd, returnType);
59 }
60 abi_aarch64::ReturnKind retKind = rtd == nullptr
62 bool retConv = rtd != nullptr
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))
79 {
80 switch (parameters[i].pTypeRef->eTypeClass) {
81#ifdef MACOSX
82 case typelib_TypeClass_BOOLEAN:
83 case typelib_TypeClass_BYTE:
84 if (ngpr < 8)
85 {
86 args[i] = gpr + ngpr;
87 ngpr++;
88 }
89 else
90 {
91 args[i] = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(stack + sp) + subsp);
92 subsp += 1;
93 if (subsp == 8)
94 {
95 sp++;
96 subsp = 0;
97 }
98 }
99 break;
100 case typelib_TypeClass_SHORT:
101 case typelib_TypeClass_UNSIGNED_SHORT:
102 case typelib_TypeClass_CHAR:
103 if (ngpr < 8)
104 {
105 args[i] = gpr + ngpr;
106 ngpr++;
107 }
108 else
109 {
110 subsp = (subsp + 1) & ~0x1;
111 if (subsp == 8)
112 {
113 sp++;
114 subsp = 0;
115 }
116 args[i] = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(stack + sp) + subsp);
117 subsp += 2;
118 if (subsp == 8)
119 {
120 sp++;
121 subsp = 0;
122 }
123 }
124 break;
125 case typelib_TypeClass_LONG:
126 case typelib_TypeClass_UNSIGNED_LONG:
127 case typelib_TypeClass_ENUM:
128 if (ngpr < 8)
129 {
130 args[i] = gpr + ngpr;
131 ngpr++;
132 }
133 else
134 {
135 subsp = (subsp + 3) & ~0x3;
136 if (subsp == 8)
137 {
138 sp++;
139 subsp = 0;
140 }
141 args[i] = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(stack + sp) + subsp);
142 subsp += 4;
143 if (subsp == 8)
144 {
145 sp++;
146 subsp = 0;
147 }
148 }
149 break;
150 case typelib_TypeClass_HYPER:
151 case typelib_TypeClass_UNSIGNED_HYPER:
152 if (ngpr < 8)
153 {
154 args[i] = gpr + ngpr;
155 ngpr++;
156 }
157 else
158 {
159 if (subsp > 0)
160 {
161 sp++;
162 subsp = 0;
163 }
164 args[i] = stack + sp;
165 sp++;
166 }
167 break;
168 case typelib_TypeClass_FLOAT:
169 if (nfpr < 8)
170 {
171 args[i] = fpr + nfpr;
172 nfpr++;
173 }
174 else
175 {
176 subsp = (subsp + 3) & ~0x3;
177 if (subsp == 8)
178 {
179 sp++;
180 subsp = 0;
181 }
182 args[i] = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(stack + sp) + subsp);
183 subsp += 4;
184 if (subsp == 8)
185 {
186 sp++;
187 subsp = 0;
188 }
189 }
190 break;
191 case typelib_TypeClass_DOUBLE:
192 if (nfpr < 8)
193 {
194 args[i] = fpr + nfpr;
195 nfpr++;
196 }
197 else
198 {
199 if (subsp > 0)
200 {
201 sp++;
202 subsp = 0;
203 }
204 args[i] = stack + sp;
205 sp++;
206 }
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);
228 }
229 argtds[i] = nullptr;
230 } else {
231#ifdef MACOSX
232 if (subsp > 0)
233 {
234 sp++;
235 subsp = 0;
236 }
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;
246 args[i] = alloca(ptd->nSize);
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);
254 }
255 }
256 }
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);
266 }
267 TYPELIB_DANGER_RELEASE(argtds[i]);
268 }
269 }
270 if (rtd != nullptr) {
271 TYPELIB_DANGER_RELEASE(rtd);
272 }
274 }
275 for (sal_Int32 i = 0; i != count; ++i) {
276 if (argtds[i] != nullptr) {
277 if (parameters[i].bOut) {
279 cppArgs[i], argtds[i],
280 reinterpret_cast<uno_ReleaseFunc>(css::uno::cpp_release));
282 cppArgs[i], args[i], argtds[i],
283 proxy->getBridge()->getUno2Cpp());
284 }
285 uno_destructData(args[i], argtds[i], nullptr);
286 TYPELIB_DANGER_RELEASE(argtds[i]);
287 }
288 }
289 void * retout = nullptr; // avoid false -Werror=maybe-uninitialized
290 switch (retKind) {
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);
346 }
347 break;
348 default:
349 assert(false);
350 }
351 break;
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);
369 }
370 assert(!retConv);
371 break;
373 assert(rtd != nullptr);
374 std::memcpy(fpr, retin, rtd->nSize);
375 assert(!retConv);
376 break;
378 retout = indirectRet;
379 break;
380 }
381 if (retConv) {
383 retout, retin, rtd, proxy->getBridge()->getUno2Cpp());
384 uno_destructData(retin, rtd, nullptr);
385 }
386 if (rtd != nullptr) {
387 TYPELIB_DANGER_RELEASE(rtd);
388 }
389}
390
391}
392
394 sal_Int32 functionIndex, sal_Int32 vtableOffset,
395 unsigned long * gpr, unsigned long * fpr, unsigned long * stack,
396 void * indirectRet)
397{
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);
422 }
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:
433 {
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) {
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;
454 }
455 TYPELIB_DANGER_RELEASE(td);
456 }
457 }
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);
469 }
470 break;
471 default:
472 assert(false);
473 }
474}
475
476namespace {
477
478std::size_t const codeSnippetSize = 8 * 4;
479
480unsigned char * generateCodeSnippet(
481 unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset)
482{
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;
502}
503
504}
505
507
510 return static_cast<Slot *>(block) + 2;
511}
512
514 sal_Int32 slotCount)
515{
516 return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
517}
518
519namespace {
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:
522struct ProxyRtti {};
523}
524
527 void * block, sal_Int32 slotCount, sal_Int32,
528 typelib_InterfaceTypeDescription *)
529{
530 Slot * slots = mapBlockToVtable(block);
531 slots[-2].fn = nullptr;
532 slots[-1].fn = &typeid(ProxyRtti);
533 return slots + slotCount;
534}
535
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)
543{
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:
555 {
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);
568 }
569 break;
570 }
571 case typelib_TypeClass_INTERFACE_METHOD:
572 (s++)->fn = code + writetoexecdiff;
573 code = generateCodeSnippet(code, functionOffset++, vtableOffset);
574 break;
575 default:
576 assert(false);
577 }
578 TYPELIB_DANGER_RELEASE(td);
579 }
580 return code;
581}
582
584 unsigned char const * begin, unsigned char const * end)
585{
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
604}
605
606/* 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
struct _typelib_TypeDescription typelib_TypeDescription
Definition: msvc/except.hxx:53
struct _uno_Any uno_Any
Definition: msvc/except.hxx:32
ReturnKind getReturnKind(typelib_TypeDescription const *type)
void raiseException(uno_Any *any, uno_Mapping *mapping)
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
enumrange< T >::Iterator begin(enumrange< T >)
end
args
sal_Unicode code
sal_uInt16 sal_Unicode
signed char sal_Int8
ResultType type
void vtableSlotCall()
#define USE_DOUBLE_MMAP
size_t pos