1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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>
40 #include <cppinterfaceproxy.hxx>
42 #include <vtablefactory.hxx>
45 #include "vtablecall.hxx"
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
*)));
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
) {
82 case typelib_TypeClass_BOOLEAN
:
83 case typelib_TypeClass_BYTE
:
91 args
[i
] = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(stack
+ sp
) + subsp
);
100 case typelib_TypeClass_SHORT
:
101 case typelib_TypeClass_UNSIGNED_SHORT
:
102 case typelib_TypeClass_CHAR
:
105 args
[i
] = gpr
+ ngpr
;
110 subsp
= (subsp
+ 1) & ~0x1;
116 args
[i
] = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(stack
+ sp
) + subsp
);
125 case typelib_TypeClass_LONG
:
126 case typelib_TypeClass_UNSIGNED_LONG
:
127 case typelib_TypeClass_ENUM
:
130 args
[i
] = gpr
+ ngpr
;
135 subsp
= (subsp
+ 3) & ~0x3;
141 args
[i
] = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(stack
+ sp
) + subsp
);
150 case typelib_TypeClass_HYPER
:
151 case typelib_TypeClass_UNSIGNED_HYPER
:
154 args
[i
] = gpr
+ ngpr
;
164 args
[i
] = stack
+ sp
;
168 case typelib_TypeClass_FLOAT
:
171 args
[i
] = fpr
+ nfpr
;
176 subsp
= (subsp
+ 3) & ~0x3;
182 args
[i
] = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(stack
+ sp
) + subsp
);
191 case typelib_TypeClass_DOUBLE
:
194 args
[i
] = fpr
+ nfpr
;
204 args
[i
] = stack
+ sp
;
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
++;
221 case typelib_TypeClass_FLOAT
:
222 case typelib_TypeClass_DOUBLE
:
223 args
[i
] = nfpr
== 8 ? stack
+ sp
++ : fpr
+ nfpr
++;
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
);
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());
251 args
[i
] = cppArgs
[i
];
253 TYPELIB_DANGER_RELEASE(ptd
);
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
) {
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
291 case abi_aarch64::RETURN_KIND_REG
:
292 switch (rtd
== nullptr ? typelib_TypeClass_VOID
: rtd
->eTypeClass
) {
293 case typelib_TypeClass_VOID
:
296 case typelib_TypeClass_BOOLEAN
:
297 assert(rtd
->nSize
== sizeof (bool));
298 *gpr
= static_cast<unsigned long>(*static_cast<bool *>(retin
));
301 case typelib_TypeClass_BYTE
:
302 assert(rtd
->nSize
== sizeof (sal_Int8
));
303 *gpr
= *static_cast<sal_Int8
*>(retin
);
306 case typelib_TypeClass_SHORT
:
307 assert(rtd
->nSize
== sizeof (sal_Int16
));
308 *gpr
= *static_cast<sal_Int16
*>(retin
);
311 case typelib_TypeClass_UNSIGNED_SHORT
:
312 assert(rtd
->nSize
== sizeof (sal_uInt16
));
313 *gpr
= *static_cast<sal_uInt16
*>(retin
);
316 case typelib_TypeClass_CHAR
:
317 assert(rtd
->nSize
== sizeof (sal_Unicode
));
318 *gpr
= *static_cast<sal_Unicode
*>(retin
);
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
:
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
);
336 case typelib_TypeClass_FLOAT
:
337 case typelib_TypeClass_DOUBLE
:
338 std::memcpy(fpr
, retin
, rtd
->nSize
);
341 case typelib_TypeClass_STRUCT
:
345 std::memcpy(gpr
, retin
, rtd
->nSize
);
352 case abi_aarch64::RETURN_KIND_HFA_FLOAT
:
353 assert(rtd
!= nullptr);
354 switch (rtd
->nSize
) {
356 std::memcpy(fpr
+ 3, static_cast<char *>(retin
) + 12, 4);
359 std::memcpy(fpr
+ 2, static_cast<char *>(retin
) + 8, 4);
362 std::memcpy(fpr
+ 1, static_cast<char *>(retin
) + 4, 4);
365 std::memcpy(fpr
, retin
, 4);
372 case abi_aarch64::RETURN_KIND_HFA_DOUBLE
:
373 assert(rtd
!= nullptr);
374 std::memcpy(fpr
, retin
, rtd
->nSize
);
377 case abi_aarch64::RETURN_KIND_INDIRECT
:
378 retout
= indirectRet
;
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
);
394 sal_Int32 functionIndex
, sal_Int32 vtableOffset
,
395 unsigned long * gpr
, unsigned long * fpr
, unsigned long * stack
,
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
) {
411 reinterpret_cast<typelib_InterfaceAttributeTypeDescription
*>(
412 desc
.get())->pAttributeTypeRef
,
413 0, nullptr, gpr
, fpr
, stack
, indirectRet
);
416 typelib_MethodParameter param
= {
418 reinterpret_cast<typelib_InterfaceAttributeTypeDescription
*>(
419 desc
.get())->pAttributeTypeRef
,
421 call(proxy
, desc
, nullptr, 1, ¶m
, gpr
, fpr
, stack
, indirectRet
);
424 case typelib_TypeClass_INTERFACE_METHOD
:
425 switch (functionIndex
) {
427 proxy
->acquireProxy();
430 proxy
->releaseProxy();
434 typelib_TypeDescription
* td
= nullptr;
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
*>(
446 if (ifc
!= nullptr) {
448 static_cast<uno_Any
*>(indirectRet
), &ifc
, td
,
449 reinterpret_cast<uno_AcquireFunc
>(
450 css::uno::cpp_acquire
));
452 TYPELIB_DANGER_RELEASE(td
);
455 TYPELIB_DANGER_RELEASE(td
);
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
);
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);
496 reinterpret_cast<unsigned int *>(code
)[4] = 0x5800004B;
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(
516 return (slotCount
+ 2) * sizeof (Slot
) + slotCount
* codeSnippetSize
;
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:
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
,
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;
547 (*slots
) -= functionCount
;
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
558 typelib_InterfaceAttributeTypeDescription
*>(td
);
560 (s
++)->fn
= code
+ writetoexecdiff
;
561 code
= generateCodeSnippet(
562 code
, functionOffset
++, vtableOffset
);
564 if (!atd
->bReadOnly
) {
565 (s
++)->fn
= code
+ writetoexecdiff
;
566 code
= generateCodeSnippet(
567 code
, functionOffset
++, vtableOffset
);
571 case typelib_TypeClass_INTERFACE_METHOD
:
572 (s
++)->fn
= code
+ writetoexecdiff
;
573 code
= generateCodeSnippet(code
, functionOffset
++, vtableOffset
);
578 TYPELIB_DANGER_RELEASE(td
);
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
);
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
)));
606 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */