summaryrefslogtreecommitdiffstats
path: root/bridges/source/cpp_uno/gcc3_linux_aarch64
diff options
context:
space:
mode:
Diffstat (limited to 'bridges/source/cpp_uno/gcc3_linux_aarch64')
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_aarch64/abi.cxx375
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_aarch64/abi.hxx157
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_aarch64/callvirtualfunction.cxx69
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_aarch64/callvirtualfunction.hxx30
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_aarch64/cpp2uno.cxx599
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_aarch64/uno2cpp.cxx519
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_aarch64/vtablecall.hxx33
-rw-r--r--bridges/source/cpp_uno/gcc3_linux_aarch64/vtableslotcall.s83
8 files changed, 1865 insertions, 0 deletions
diff --git a/bridges/source/cpp_uno/gcc3_linux_aarch64/abi.cxx b/bridges/source/cpp_uno/gcc3_linux_aarch64/abi.cxx
new file mode 100644
index 000000000..ff50e62dd
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_aarch64/abi.cxx
@@ -0,0 +1,375 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <typeinfo>
+
+#include <dlfcn.h>
+
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/genfunc.h>
+#include <o3tl/string_view.hxx>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+#include <typelib/typeclass.h>
+#include <typelib/typedescription.h>
+#include <uno/any2.h>
+#include <uno/mapping.h>
+
+#include "abi.hxx"
+#include <osl/mutex.hxx>
+#include <unordered_map>
+
+namespace {
+
+OUString toUnoName(char const * name) {
+ assert(name != nullptr);
+ OUStringBuffer b;
+ bool scoped = *name == 'N';
+ if (scoped) {
+ ++name;
+ }
+ for (;;) {
+ assert(*name >= '0' && *name <= '9');
+ std::size_t n = *name++ - '0';
+ while (*name >= '0' && *name <= '9') {
+ n = 10 * n + (*name++ - '0');
+ }
+ b.appendAscii(name, n);
+ name += n;
+ if (!scoped) {
+ assert(*name == 0);
+ break;
+ }
+ if (*name == 'E') {
+ assert(name[1] == 0);
+ break;
+ }
+ b.append('.');
+ }
+ return b.makeStringAndClear();
+}
+
+class Rtti {
+public:
+ Rtti(): app_(dlopen(nullptr, RTLD_LAZY)) {}
+
+ ~Rtti() { dlclose(app_); }
+
+ std::type_info * getRtti(typelib_TypeDescription const & type);
+
+private:
+ typedef std::unordered_map<OUString, std::type_info *> Map;
+
+ void * app_;
+
+ osl::Mutex mutex_;
+ Map map_;
+};
+
+std::type_info * Rtti::getRtti(typelib_TypeDescription const & type) {
+ OUString unoName(type.pTypeName);
+ osl::MutexGuard g(mutex_);
+ Map::iterator i(map_.find(unoName));
+ if (i == map_.end()) {
+ OStringBuffer b;
+ b.append("_ZTIN");
+ for (sal_Int32 j = 0; j != -1;) {
+ OString t(
+ OUStringToOString(
+ o3tl::getToken(unoName, 0, '.', j), RTL_TEXTENCODING_ASCII_US));
+ b.append(t.getLength());
+ b.append(t);
+ }
+ b.append('E');
+ OString sym(b.makeStringAndClear());
+ std::type_info * rtti = static_cast<std::type_info *>(
+ dlsym(app_, sym.getStr()));
+ if (rtti == nullptr) {
+ char const * rttiName = strdup(sym.getStr() + std::strlen("_ZTI"));
+ if (rttiName == nullptr) {
+ throw std::bad_alloc();
+ }
+#if defined MACOSX
+ // For the Apple ARM64 ABI, if the most significant ("non-unique RTTI") bit is set, it
+ // means that the instance of the name is not unique (and thus RTTI equality needs to be
+ // determined by string comparison rather than by pointer comparison):
+ rttiName = reinterpret_cast<char const *>(
+ reinterpret_cast<std::uintptr_t>(rttiName) | 0x8000'0000'0000'0000);
+#endif
+ assert(type.eTypeClass == typelib_TypeClass_EXCEPTION);
+ typelib_CompoundTypeDescription const & ctd
+ = reinterpret_cast<typelib_CompoundTypeDescription const &>(
+ type);
+ if (ctd.pBaseTypeDescription == nullptr) {
+ rtti = new __cxxabiv1::__class_type_info(rttiName);
+ } else {
+ std::type_info * base = getRtti(
+ ctd.pBaseTypeDescription->aBase);
+ rtti = new __cxxabiv1::__si_class_type_info(
+ rttiName,
+ static_cast<__cxxabiv1::__class_type_info *>(base));
+ }
+ }
+ i = map_.insert(Map::value_type(unoName, rtti)).first;
+ }
+ return i->second;
+}
+
+struct theRttiFactory: public rtl::Static<Rtti, theRttiFactory> {};
+
+std::type_info * getRtti(typelib_TypeDescription const & type) {
+ return theRttiFactory::get().getRtti(type);
+}
+
+extern "C" void _GLIBCXX_CDTOR_CALLABI deleteException(void * exception) {
+ __cxxabiv1::__cxa_exception * header =
+ static_cast<__cxxabiv1::__cxa_exception *>(exception) - 1;
+#if !defined MACOSX && defined _LIBCPPABI_VERSION // detect libc++abi
+ // First, the libcxxabi commit
+ // <http://llvm.org/viewvc/llvm-project?view=revision&revision=303175>
+ // "[libcxxabi] Align unwindHeader on a double-word boundary" towards
+ // LLVM 5.0 changed the size of __cxa_exception by adding
+ //
+ // __attribute__((aligned))
+ //
+ // to the final member unwindHeader, on x86-64 effectively adding a hole of
+ // size 8 in front of that member (changing its offset from 88 to 96,
+ // sizeof(__cxa_exception) from 120 to 128, and alignof(__cxa_exception)
+ // from 8 to 16); the "header1" hack below to dynamically determine whether we run against a
+ // LLVM 5 libcxxabi is to look at the exceptionDestructor member, which must
+ // point to this function (the use of __cxa_exception in mapException is
+ // unaffected, as it only accesses members towards the start of the struct,
+ // through a pointer known to actually point at the start). The libcxxabi commit
+ // <https://github.com/llvm/llvm-project/commit/9ef1daa46edb80c47d0486148c0afc4e0d83ddcf>
+ // "Insert padding before the __cxa_exception header to ensure the thrown" in LLVM 6
+ // removes the need for this hack, so the "header1" hack can be removed again once we can be
+ // sure that we only run against libcxxabi from LLVM >= 6.
+ //
+ // Second, the libcxxabi commit
+ // <https://github.com/llvm/llvm-project/commit/674ec1eb16678b8addc02a4b0534ab383d22fa77>
+ // "[libcxxabi] Insert padding in __cxa_exception struct for compatibility" in LLVM 10 changed
+ // the layout of the start of __cxa_exception to
+ //
+ // [8 byte void *reserve]
+ // 8 byte size_t referenceCount
+ //
+ // so the "header2" hack below to dynamically determine whether we run against a LLVM >= 10
+ // libcxxabi is to look whether the exceptionDestructor (with its known value) has increased its
+ // offset by 8. As described in the definition of __cxa_exception
+ // (bridges/source/cpp_uno/gcc3_linux_aarch64/abi.hxx), the "header2" hack (together with the
+ // "#ifdef MACOSX" in the definition of __cxa_exception and the corresponding hack in call in
+ // bridges/source/cpp_uno/gcc3_linux_aarch64/uno2cpp.cxx) can be dropped once we can be sure
+ // that we only run against new libcxxabi that has the reserve member.
+ if (header->exceptionDestructor != &deleteException) {
+ auto const header1 = reinterpret_cast<__cxxabiv1::__cxa_exception *>(
+ reinterpret_cast<char *>(header) - 8);
+ if (header1->exceptionDestructor == &deleteException) {
+ header = header1;
+ } else {
+ auto const header2 = reinterpret_cast<__cxxabiv1::__cxa_exception *>(
+ reinterpret_cast<char *>(header) + 8);
+ if (header2->exceptionDestructor == &deleteException) {
+ header = header2;
+ } else {
+ assert(false);
+ }
+ }
+ }
+#endif
+ assert(header->exceptionDestructor == &deleteException);
+ OUString unoName(toUnoName(header->exceptionType->name()));
+ typelib_TypeDescription * td = nullptr;
+ typelib_typedescription_getByName(&td, unoName.pData);
+ assert(td != nullptr);
+ uno_destructData(exception, td, &css::uno::cpp_release);
+ typelib_typedescription_release(td);
+}
+
+enum StructKind {
+ STRUCT_KIND_EMPTY, STRUCT_KIND_FLOAT, STRUCT_KIND_DOUBLE, STRUCT_KIND_POD,
+ STRUCT_KIND_DTOR
+};
+
+StructKind getStructKind(typelib_CompoundTypeDescription const * type) {
+ StructKind k = type->pBaseTypeDescription == nullptr
+ ? STRUCT_KIND_EMPTY : getStructKind(type->pBaseTypeDescription);
+ for (sal_Int32 i = 0; i != type->nMembers; ++i) {
+ StructKind k2 = StructKind();
+ switch (type->ppTypeRefs[i]->eTypeClass) {
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_ENUM:
+ k2 = STRUCT_KIND_POD;
+ break;
+ case typelib_TypeClass_FLOAT:
+ k2 = STRUCT_KIND_FLOAT;
+ break;
+ case typelib_TypeClass_DOUBLE:
+ k2 = STRUCT_KIND_DOUBLE;
+ break;
+ case typelib_TypeClass_STRING:
+ case typelib_TypeClass_TYPE:
+ case typelib_TypeClass_ANY:
+ case typelib_TypeClass_SEQUENCE:
+ case typelib_TypeClass_INTERFACE:
+ k2 = STRUCT_KIND_DTOR;
+ break;
+ case typelib_TypeClass_STRUCT:
+ {
+ typelib_TypeDescription * td = nullptr;
+ TYPELIB_DANGER_GET(&td, type->ppTypeRefs[i]);
+ k2 = getStructKind(
+ reinterpret_cast<typelib_CompoundTypeDescription const *>(
+ td));
+ TYPELIB_DANGER_RELEASE(td);
+ break;
+ }
+ default:
+ assert(false);
+ }
+ switch (k2) {
+ case STRUCT_KIND_EMPTY:
+ // this means an empty sub-object, which nevertheless obtains a byte
+ // of storage (TODO: does it?), so the full object cannot be a
+ // homogeneous collection of float or double
+ case STRUCT_KIND_POD:
+ assert(k != STRUCT_KIND_DTOR);
+ k = STRUCT_KIND_POD;
+ break;
+ case STRUCT_KIND_FLOAT:
+ case STRUCT_KIND_DOUBLE:
+ if (k == STRUCT_KIND_EMPTY) {
+ k = k2;
+ } else if (k != k2) {
+ assert(k != STRUCT_KIND_DTOR);
+ k = STRUCT_KIND_POD;
+ }
+ break;
+ case STRUCT_KIND_DTOR:
+ return STRUCT_KIND_DTOR;
+ }
+ }
+ return k;
+}
+
+}
+
+namespace abi_aarch64 {
+
+void mapException(
+ __cxxabiv1::__cxa_exception * exception, std::type_info const * type, uno_Any * any, uno_Mapping * mapping)
+{
+ assert(exception != nullptr);
+ assert(type != nullptr);
+ OUString unoName(toUnoName(type->name()));
+ typelib_TypeDescription * td = nullptr;
+ typelib_typedescription_getByName(&td, unoName.pData);
+ if (td == nullptr) {
+ css::uno::RuntimeException e("exception type not found: " + unoName);
+ uno_type_any_constructAndConvert(
+ any, &e,
+ cppu::UnoType<css::uno::RuntimeException>::get().getTypeLibType(),
+ mapping);
+ } else {
+ uno_any_constructAndConvert(any, exception->adjustedPtr, td, mapping);
+ typelib_typedescription_release(td);
+ }
+}
+
+void raiseException(uno_Any * any, uno_Mapping * mapping) {
+ typelib_TypeDescription * td = nullptr;
+ TYPELIB_DANGER_GET(&td, any->pType);
+ if (td == nullptr) {
+ throw css::uno::RuntimeException(
+ "no typedescription for " + OUString::unacquired(&any->pType->pTypeName));
+ }
+ void * exc = __cxxabiv1::__cxa_allocate_exception(td->nSize);
+ uno_copyAndConvertData(exc, any->pData, td, mapping);
+ uno_any_destruct(any, nullptr);
+ std::type_info * rtti = getRtti(*td);
+ TYPELIB_DANGER_RELEASE(td);
+ __cxxabiv1::__cxa_throw(exc, rtti, deleteException);
+}
+
+ReturnKind getReturnKind(typelib_TypeDescription const * type) {
+ switch (type->eTypeClass) {
+ default:
+ assert(false);
+#ifdef NDEBUG
+ [[fallthrough]];
+#endif
+ case typelib_TypeClass_VOID:
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_ENUM:
+ assert(type->nSize <= 16);
+ return RETURN_KIND_REG;
+ case typelib_TypeClass_STRING:
+ case typelib_TypeClass_TYPE:
+ case typelib_TypeClass_ANY:
+ case typelib_TypeClass_SEQUENCE:
+ case typelib_TypeClass_INTERFACE:
+ return RETURN_KIND_INDIRECT;
+ case typelib_TypeClass_STRUCT:
+ if (type->nSize > 16) {
+ return RETURN_KIND_INDIRECT;
+ }
+ switch (getStructKind(
+ reinterpret_cast<typelib_CompoundTypeDescription const *>(
+ type)))
+ {
+ case STRUCT_KIND_FLOAT:
+ return RETURN_KIND_HFA_FLOAT;
+ case STRUCT_KIND_DOUBLE:
+ return RETURN_KIND_HFA_DOUBLE;
+ case STRUCT_KIND_DTOR:
+ return RETURN_KIND_INDIRECT;
+ default:
+ return RETURN_KIND_REG;
+ }
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_aarch64/abi.hxx b/bridges/source/cpp_uno/gcc3_linux_aarch64/abi.hxx
new file mode 100644
index 000000000..10495582d
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_aarch64/abi.hxx
@@ -0,0 +1,157 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <cstddef>
+#include <exception>
+#include <typeinfo>
+
+#include <cxxabi.h>
+#ifndef _GLIBCXX_CDTOR_CALLABI // new in GCC 4.7 cxxabi.h
+#define _GLIBCXX_CDTOR_CALLABI
+#endif
+#include <unwind.h>
+
+#include <config_cxxabi.h>
+#include <typelib/typedescription.h>
+#include <uno/any2.h>
+#include <uno/mapping.h>
+
+#if !HAVE_CXXABI_H_CLASS_TYPE_INFO
+// <https://mentorembedded.github.io/cxx-abi/abi.html>,
+// libstdc++-v3/libsupc++/cxxabi.h:
+namespace __cxxabiv1 {
+class __class_type_info: public std::type_info {
+public:
+ explicit __class_type_info(char const * n): type_info(n) {}
+ ~__class_type_info() override;
+};
+}
+#endif
+
+#if !HAVE_CXXABI_H_SI_CLASS_TYPE_INFO
+// <https://mentorembedded.github.io/cxx-abi/abi.html>,
+// libstdc++-v3/libsupc++/cxxabi.h:
+namespace __cxxabiv1 {
+class __si_class_type_info: public __class_type_info {
+public:
+ __class_type_info const * __base_type;
+ explicit __si_class_type_info(
+ char const * n, __class_type_info const *base):
+ __class_type_info(n), __base_type(base) {}
+ ~__si_class_type_info() override;
+};
+}
+#endif
+
+#if !HAVE_CXXABI_H_CXA_EXCEPTION
+// <https://mentorembedded.github.io/cxx-abi/abi-eh.html>,
+// libcxxabi/src/cxa_exception.hpp:
+namespace __cxxabiv1 {
+struct __cxa_exception {
+#if defined _LIBCPPABI_VERSION // detect libc++abi
+#if defined __LP64__ || LIBCXXABI_ARM_EHABI
+#ifdef MACOSX // on arm64
+ // This is a new field added with LLVM 10
+ // <https://github.com/llvm/llvm-project/commit/674ec1eb16678b8addc02a4b0534ab383d22fa77>
+ // "[libcxxabi] Insert padding in __cxa_exception struct for compatibility". For non-MACOSX,
+ // the HACK in call (bridges/source/cpp_uno/gcc3_linux_aarch64/uno2cpp.cxx) tries to find out at
+ // runtime whether a __cxa_exception has this member. Once we can be sure that we only run
+ // against new libcxxabi that has this member, we can drop the "#ifdef MACOSX" here and drop the
+ // hack in call.
+
+ // Now _Unwind_Exception is marked with __attribute__((aligned)),
+ // which implies __cxa_exception is also aligned. Insert padding
+ // in the beginning of the struct, rather than before unwindHeader.
+ void *reserve;
+#endif
+ std::size_t referenceCount;
+#endif
+#endif
+ std::type_info * exceptionType;
+ void (* exceptionDestructor)(void *);
+ void (*unexpectedHandler)(); // std::unexpected_handler dropped from C++17
+ std::terminate_handler terminateHandler;
+ __cxa_exception * nextException;
+ int handlerCount;
+ int handlerSwitchValue;
+ char const * actionRecord;
+ char const * languageSpecificData;
+ void * catchTemp;
+ void * adjustedPtr;
+ _Unwind_Exception unwindHeader;
+};
+}
+#endif
+
+#if !HAVE_CXXABI_H_CXA_EH_GLOBALS
+// <https://mentorembedded.github.io/cxx-abi/abi-eh.html>:
+namespace __cxxabiv1 {
+struct __cxa_eh_globals {
+ __cxa_exception * caughtExceptions;
+ unsigned int uncaughtExceptions;
+};
+}
+#endif
+
+#if !HAVE_CXXABI_H_CXA_GET_GLOBALS
+namespace __cxxabiv1 {
+extern "C" __cxa_eh_globals * __cxa_get_globals() noexcept;
+}
+#endif
+
+#if !HAVE_CXXABI_H_CXA_CURRENT_EXCEPTION_TYPE
+namespace __cxxabiv1 {
+extern "C" std::type_info *__cxa_current_exception_type() throw();
+}
+#endif
+
+#if !HAVE_CXXABI_H_CXA_ALLOCATE_EXCEPTION
+namespace __cxxabiv1 {
+extern "C" void * __cxa_allocate_exception(std::size_t thrown_size) throw();
+}
+#endif
+
+#if !HAVE_CXXABI_H_CXA_THROW
+namespace __cxxabiv1 {
+extern "C" void __cxa_throw(
+ void * thrown_exception, void * tinfo, void (* dest)(void *))
+ __attribute__((noreturn));
+}
+#endif
+
+namespace abi_aarch64 {
+
+void mapException(
+ __cxxabiv1::__cxa_exception * exception, std::type_info const * type, uno_Any * any, uno_Mapping * mapping);
+
+void raiseException(uno_Any * any, uno_Mapping * mapping);
+
+enum ReturnKind {
+ RETURN_KIND_REG, RETURN_KIND_HFA_FLOAT, RETURN_KIND_HFA_DOUBLE,
+ RETURN_KIND_INDIRECT };
+
+ReturnKind getReturnKind(typelib_TypeDescription const * type);
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_aarch64/callvirtualfunction.cxx b/bridges/source/cpp_uno/gcc3_linux_aarch64/callvirtualfunction.cxx
new file mode 100644
index 000000000..b944f31cf
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_aarch64/callvirtualfunction.cxx
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cstring>
+
+#include <sal/types.h>
+#include <sal/alloca.h>
+
+#include "callvirtualfunction.hxx"
+
+void callVirtualFunction(
+ unsigned long function, unsigned long * gpr, unsigned long * fpr,
+ unsigned long * stack, sal_Int32 sp, void * ret)
+{
+ void * stackargs;
+ if (sp != 0) {
+ stackargs = alloca(((sp + 1) >> 1) * 16);
+ std::memcpy(stackargs, stack, sp * 8);
+ }
+ asm volatile(
+ "ldp x0, x1, [%[gpr_]]\n\t"
+ "ldp x2, x3, [%[gpr_], #16]\n\t"
+ "ldp x4, x5, [%[gpr_], #32]\n\t"
+ "ldp x6, x7, [%[gpr_], #48]\n\t"
+ "ldr x8, %[ret_]\n\t"
+ "ldr x9, %[function_]\n\t"
+ "ldp d0, d1, [%[fpr_]]\n\t"
+ "ldp d2, d3, [%[fpr_], #16]\n\t"
+ "ldp d4, d5, [%[fpr_], #32]\n\t"
+ "ldp d6, d7, [%[fpr_], #48]\n\t"
+ "blr x9\n\t"
+ "stp x0, x1, [%[gpr_]]\n\t"
+ "stp d0, d1, [%[fpr_]]\n\t"
+ "stp d2, d3, [%[fpr_], #16]\n\t"
+ :: [gpr_]"r" (gpr), [fpr_]"r" (fpr), [function_]"m" (function),
+ [ret_]"m" (ret),
+ "m" (stackargs) // dummy input to prevent optimizing the alloca away
+ : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
+ "r11", "r12", "r13", "r14", "r15", "r16", "r17",
+#if !defined ANDROID && !defined MACOSX
+ "r18"/*TODO?*/,
+#endif
+ "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11",
+ "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21",
+ "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31",
+ "memory"
+ // only the bottom 64 bits of v8--15 need to be preserved by callees
+ );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_aarch64/callvirtualfunction.hxx b/bridges/source/cpp_uno/gcc3_linux_aarch64/callvirtualfunction.hxx
new file mode 100644
index 000000000..a8b92785f
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_aarch64/callvirtualfunction.hxx
@@ -0,0 +1,30 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <sal/types.h>
+
+void callVirtualFunction(
+ unsigned long function, unsigned long * gpr, unsigned long * fpr,
+ unsigned long * stack, sal_Int32 sp, void * ret);
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_aarch64/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_aarch64/cpp2uno.cxx
new file mode 100644
index 000000000..775a4aff6
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_aarch64/cpp2uno.cxx
@@ -0,0 +1,599 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+#include <cstdarg>
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+
+#include <dlfcn.h>
+
+#include <com/sun/star/uno/XInterface.hpp>
+#include <com/sun/star/uno/genfunc.hxx>
+#include <sal/alloca.h>
+#include <sal/types.h>
+#include <typelib/typeclass.h>
+#include <typelib/typedescription.h>
+#include <typelib/typedescription.hxx>
+
+#include <bridge.hxx>
+#include <cppinterfaceproxy.hxx>
+#include <types.hxx>
+#include <vtablefactory.hxx>
+
+#include "abi.hxx"
+#include "vtablecall.hxx"
+
+namespace {
+
+void call(
+ bridges::cpp_uno::shared::CppInterfaceProxy * proxy,
+ css::uno::TypeDescription const & description,
+ typelib_TypeDescriptionReference * returnType, sal_Int32 count,
+ typelib_MethodParameter * parameters, unsigned long * gpr,
+ unsigned long * fpr, unsigned long * stack, void * indirectRet)
+{
+ typelib_TypeDescription * rtd = nullptr;
+ if (returnType != nullptr) {
+ TYPELIB_DANGER_GET(&rtd, returnType);
+ }
+ abi_aarch64::ReturnKind retKind = rtd == nullptr
+ ? abi_aarch64::RETURN_KIND_REG : abi_aarch64::getReturnKind(rtd);
+ bool retConv = rtd != nullptr
+ && bridges::cpp_uno::shared::relatesToInterfaceType(rtd);
+ void * retin = retKind == abi_aarch64::RETURN_KIND_INDIRECT && !retConv
+ ? indirectRet : rtd == nullptr ? nullptr : alloca(rtd->nSize);
+ void ** args = static_cast< void ** >(alloca(count * sizeof (void *)));
+ void ** cppArgs = static_cast< void ** >(alloca(count * sizeof (void *)));
+ typelib_TypeDescription ** argtds = static_cast<typelib_TypeDescription **>(
+ alloca(count * sizeof (typelib_TypeDescription *)));
+ sal_Int32 ngpr = 1;
+ sal_Int32 nfpr = 0;
+ sal_Int32 sp = 0;
+#ifdef MACOSX
+ sal_Int32 subsp = 0;
+#endif
+ for (sal_Int32 i = 0; i != count; ++i) {
+ if (!parameters[i].bOut
+ && bridges::cpp_uno::shared::isSimpleType(parameters[i].pTypeRef))
+ {
+ switch (parameters[i].pTypeRef->eTypeClass) {
+#ifdef MACOSX
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ if (ngpr < 8)
+ {
+ args[i] = gpr + ngpr;
+ ngpr++;
+ }
+ else
+ {
+ args[i] = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(stack + sp) + subsp);
+ subsp += 1;
+ if (subsp == 8)
+ {
+ sp++;
+ subsp = 0;
+ }
+ }
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ case typelib_TypeClass_CHAR:
+ if (ngpr < 8)
+ {
+ args[i] = gpr + ngpr;
+ ngpr++;
+ }
+ else
+ {
+ subsp = (subsp + 1) & ~0x1;
+ if (subsp == 8)
+ {
+ sp++;
+ subsp = 0;
+ }
+ args[i] = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(stack + sp) + subsp);
+ subsp += 2;
+ if (subsp == 8)
+ {
+ sp++;
+ subsp = 0;
+ }
+ }
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ if (ngpr < 8)
+ {
+ args[i] = gpr + ngpr;
+ ngpr++;
+ }
+ else
+ {
+ subsp = (subsp + 3) & ~0x3;
+ if (subsp == 8)
+ {
+ sp++;
+ subsp = 0;
+ }
+ args[i] = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(stack + sp) + subsp);
+ subsp += 4;
+ if (subsp == 8)
+ {
+ sp++;
+ subsp = 0;
+ }
+ }
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ if (ngpr < 8)
+ {
+ args[i] = gpr + ngpr;
+ ngpr++;
+ }
+ else
+ {
+ if (subsp > 0)
+ {
+ sp++;
+ subsp = 0;
+ }
+ args[i] = stack + sp;
+ sp++;
+ }
+ break;
+ case typelib_TypeClass_FLOAT:
+ if (nfpr < 8)
+ {
+ args[i] = fpr + nfpr;
+ nfpr++;
+ }
+ else
+ {
+ subsp = (subsp + 3) & ~0x3;
+ if (subsp == 8)
+ {
+ sp++;
+ subsp = 0;
+ }
+ args[i] = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(stack + sp) + subsp);
+ subsp += 4;
+ if (subsp == 8)
+ {
+ sp++;
+ subsp = 0;
+ }
+ }
+ break;
+ case typelib_TypeClass_DOUBLE:
+ if (nfpr < 8)
+ {
+ args[i] = fpr + nfpr;
+ nfpr++;
+ }
+ else
+ {
+ if (subsp > 0)
+ {
+ sp++;
+ subsp = 0;
+ }
+ args[i] = stack + sp;
+ sp++;
+ }
+ break;
+#else
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_ENUM:
+ args[i] = ngpr == 8 ? stack + sp++ : gpr + ngpr++;
+ break;
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ args[i] = nfpr == 8 ? stack + sp++ : fpr + nfpr++;
+ break;
+#endif
+ default:
+ assert(false);
+ }
+ argtds[i] = nullptr;
+ } else {
+#ifdef MACOSX
+ if (subsp > 0)
+ {
+ sp++;
+ subsp = 0;
+ }
+#endif
+ cppArgs[i] = reinterpret_cast<void *>(
+ ngpr == 8 ? stack[sp++] : gpr[ngpr++]);
+ typelib_TypeDescription * ptd = nullptr;
+ TYPELIB_DANGER_GET(&ptd, parameters[i].pTypeRef);
+ if (!parameters[i].bIn) {
+ args[i] = alloca(ptd->nSize);
+ argtds[i] = ptd;
+ } else if (bridges::cpp_uno::shared::relatesToInterfaceType(ptd)) {
+ args[i] = alloca(ptd->nSize);
+ uno_copyAndConvertData(
+ args[i], cppArgs[i], ptd, proxy->getBridge()->getCpp2Uno());
+ argtds[i] = ptd;
+ } else {
+ args[i] = cppArgs[i];
+ argtds[i] = nullptr;
+ TYPELIB_DANGER_RELEASE(ptd);
+ }
+ }
+ }
+ uno_Any exc;
+ uno_Any * pexc = &exc;
+ proxy->getUnoI()->pDispatcher(
+ proxy->getUnoI(), description.get(), retin, args, &pexc);
+ if (pexc != nullptr) {
+ for (sal_Int32 i = 0; i != count; ++i) {
+ if (argtds[i] != nullptr) {
+ if (parameters[i].bIn) {
+ uno_destructData(args[i], argtds[i], nullptr);
+ }
+ TYPELIB_DANGER_RELEASE(argtds[i]);
+ }
+ }
+ if (rtd != nullptr) {
+ TYPELIB_DANGER_RELEASE(rtd);
+ }
+ abi_aarch64::raiseException(&exc, proxy->getBridge()->getUno2Cpp());
+ }
+ for (sal_Int32 i = 0; i != count; ++i) {
+ if (argtds[i] != nullptr) {
+ if (parameters[i].bOut) {
+ uno_destructData(
+ cppArgs[i], argtds[i],
+ reinterpret_cast<uno_ReleaseFunc>(css::uno::cpp_release));
+ uno_copyAndConvertData(
+ cppArgs[i], args[i], argtds[i],
+ proxy->getBridge()->getUno2Cpp());
+ }
+ uno_destructData(args[i], argtds[i], nullptr);
+ TYPELIB_DANGER_RELEASE(argtds[i]);
+ }
+ }
+ void * retout = nullptr; // avoid false -Werror=maybe-uninitialized
+ switch (retKind) {
+ case abi_aarch64::RETURN_KIND_REG:
+ switch (rtd == nullptr ? typelib_TypeClass_VOID : rtd->eTypeClass) {
+ case typelib_TypeClass_VOID:
+ break;
+#if defined MACOSX
+ case typelib_TypeClass_BOOLEAN:
+ assert(rtd->nSize == sizeof (bool));
+ *gpr = static_cast<unsigned long>(*static_cast<bool *>(retin));
+ assert(!retConv);
+ break;
+ case typelib_TypeClass_BYTE:
+ assert(rtd->nSize == sizeof (sal_Int8));
+ *gpr = *static_cast<sal_Int8 *>(retin);
+ assert(!retConv);
+ break;
+ case typelib_TypeClass_SHORT:
+ assert(rtd->nSize == sizeof (sal_Int16));
+ *gpr = *static_cast<sal_Int16 *>(retin);
+ assert(!retConv);
+ break;
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ assert(rtd->nSize == sizeof (sal_uInt16));
+ *gpr = *static_cast<sal_uInt16 *>(retin);
+ assert(!retConv);
+ break;
+ case typelib_TypeClass_CHAR:
+ assert(rtd->nSize == sizeof (sal_Unicode));
+ *gpr = *static_cast<sal_Unicode *>(retin);
+ assert(!retConv);
+ break;
+#else
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ case typelib_TypeClass_CHAR:
+#endif
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_ENUM:
+ std::memcpy(gpr, retin, rtd->nSize);
+ assert(!retConv);
+ break;
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ std::memcpy(fpr, retin, rtd->nSize);
+ assert(!retConv);
+ break;
+ case typelib_TypeClass_STRUCT:
+ if (retConv) {
+ retout = gpr;
+ } else {
+ std::memcpy(gpr, retin, rtd->nSize);
+ }
+ break;
+ default:
+ assert(false);
+ }
+ break;
+ case abi_aarch64::RETURN_KIND_HFA_FLOAT:
+ assert(rtd != nullptr);
+ switch (rtd->nSize) {
+ case 16:
+ std::memcpy(fpr + 3, static_cast<char *>(retin) + 12, 4);
+ [[fallthrough]];
+ case 12:
+ std::memcpy(fpr + 2, static_cast<char *>(retin) + 8, 4);
+ [[fallthrough]];
+ case 8:
+ std::memcpy(fpr + 1, static_cast<char *>(retin) + 4, 4);
+ [[fallthrough]];
+ case 4:
+ std::memcpy(fpr, retin, 4);
+ break;
+ default:
+ assert(false);
+ }
+ assert(!retConv);
+ break;
+ case abi_aarch64::RETURN_KIND_HFA_DOUBLE:
+ assert(rtd != nullptr);
+ std::memcpy(fpr, retin, rtd->nSize);
+ assert(!retConv);
+ break;
+ case abi_aarch64::RETURN_KIND_INDIRECT:
+ retout = indirectRet;
+ break;
+ }
+ if (retConv) {
+ uno_copyAndConvertData(
+ retout, retin, rtd, proxy->getBridge()->getUno2Cpp());
+ uno_destructData(retin, rtd, nullptr);
+ }
+ if (rtd != nullptr) {
+ TYPELIB_DANGER_RELEASE(rtd);
+ }
+}
+
+}
+
+void vtableCall(
+ sal_Int32 functionIndex, sal_Int32 vtableOffset,
+ unsigned long * gpr, unsigned long * fpr, unsigned long * stack,
+ void * indirectRet)
+{
+ bridges::cpp_uno::shared::CppInterfaceProxy * proxy
+ = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
+ reinterpret_cast<char *>(gpr[0]) - vtableOffset);
+ typelib_InterfaceTypeDescription * type = proxy->getTypeDescr();
+ assert(functionIndex < type->nMapFunctionIndexToMemberIndex);
+ sal_Int32 pos = type->pMapFunctionIndexToMemberIndex[functionIndex];
+ css::uno::TypeDescription desc(type->ppAllMembers[pos]);
+ switch (desc.get()->eTypeClass) {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ if (type->pMapMemberIndexToFunctionIndex[pos] == functionIndex) {
+ // Getter:
+ call(
+ proxy, desc,
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>(
+ desc.get())->pAttributeTypeRef,
+ 0, nullptr, gpr, fpr, stack, indirectRet);
+ } else {
+ // Setter:
+ typelib_MethodParameter param = {
+ nullptr,
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>(
+ desc.get())->pAttributeTypeRef,
+ true, false };
+ call(proxy, desc, nullptr, 1, &param, gpr, fpr, stack, indirectRet);
+ }
+ break;
+ case typelib_TypeClass_INTERFACE_METHOD:
+ switch (functionIndex) {
+ case 1:
+ proxy->acquireProxy();
+ break;
+ case 2:
+ proxy->releaseProxy();
+ break;
+ case 0:
+ {
+ typelib_TypeDescription * td = nullptr;
+ TYPELIB_DANGER_GET(
+ &td,
+ (reinterpret_cast<css::uno::Type *>(gpr[1])
+ ->getTypeLibType()));
+ if (td != nullptr && td->eTypeClass == typelib_TypeClass_INTERFACE) {
+ css::uno::XInterface * ifc = nullptr;
+ proxy->getBridge()->getCppEnv()->getRegisteredInterface(
+ proxy->getBridge()->getCppEnv(),
+ reinterpret_cast<void **>(&ifc), proxy->getOid().pData,
+ reinterpret_cast<typelib_InterfaceTypeDescription *>(
+ td));
+ if (ifc != nullptr) {
+ uno_any_construct(
+ static_cast<uno_Any *>(indirectRet), &ifc, td,
+ reinterpret_cast<uno_AcquireFunc>(
+ css::uno::cpp_acquire));
+ ifc->release();
+ TYPELIB_DANGER_RELEASE(td);
+ break;
+ }
+ TYPELIB_DANGER_RELEASE(td);
+ }
+ }
+ [[fallthrough]];
+ default:
+ call(
+ proxy, desc,
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription *>(
+ desc.get())->pReturnTypeRef,
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription *>(
+ desc.get())->nParams,
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription *>(
+ desc.get())->pParams,
+ gpr, fpr, stack, indirectRet);
+ }
+ break;
+ default:
+ assert(false);
+ }
+}
+
+namespace {
+
+std::size_t const codeSnippetSize = 8 * 4;
+
+unsigned char * generateCodeSnippet(
+ unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset)
+{
+ // movz x9, <low functionIndex>
+ reinterpret_cast<unsigned int *>(code)[0] = 0xD2800009
+ | ((functionIndex & 0xFFFF) << 5);
+ // movk x9, <high functionIndex>, LSL #16
+ reinterpret_cast<unsigned int *>(code)[1] = 0xF2A00009
+ | ((functionIndex >> 16) << 5);
+ // movz x10, <low vtableOffset>
+ reinterpret_cast<unsigned int *>(code)[2] = 0xD280000A
+ | ((vtableOffset & 0xFFFF) << 5);
+ // movk x10, <high vtableOffset>, LSL #16
+ reinterpret_cast<unsigned int *>(code)[3] = 0xF2A0000A
+ | ((vtableOffset >> 16) << 5);
+ // ldr x11, +2*4
+ reinterpret_cast<unsigned int *>(code)[4] = 0x5800004B;
+ // br x11
+ reinterpret_cast<unsigned int *>(code)[5] = 0xD61F0160;
+ reinterpret_cast<unsigned long *>(code)[3]
+ = reinterpret_cast<unsigned long>(&vtableSlotCall);
+ return code + codeSnippetSize;
+}
+
+}
+
+struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; };
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) {
+ return static_cast<Slot *>(block) + 2;
+}
+
+std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(
+ sal_Int32 slotCount)
+{
+ return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
+}
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::initializeBlock(
+ void * block, sal_Int32 slotCount, sal_Int32,
+ typelib_InterfaceTypeDescription *)
+{
+ Slot * slots = mapBlockToVtable(block);
+ slots[-2].fn = nullptr;
+ slots[-1].fn = nullptr;
+ return slots + slotCount;
+}
+
+unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
+ Slot ** slots, unsigned char * code,
+#ifdef USE_DOUBLE_MMAP
+ sal_PtrDiff writetoexecdiff,
+#endif
+ typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
+ sal_Int32 functionCount, sal_Int32 vtableOffset)
+{
+#ifndef USE_DOUBLE_MMAP
+ constexpr sal_PtrDiff writetoexecdiff = 0;
+#endif
+ (*slots) -= functionCount;
+ Slot * s = *slots;
+ for (sal_Int32 i = 0; i != type->nMembers; ++i) {
+ typelib_TypeDescription * td = nullptr;
+ TYPELIB_DANGER_GET(&td, type->ppMembers[i]);
+ assert(td != nullptr);
+ switch (td->eTypeClass) {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ typelib_InterfaceAttributeTypeDescription * atd
+ = reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription *>(td);
+ // Getter:
+ (s++)->fn = code + writetoexecdiff;
+ code = generateCodeSnippet(
+ code, functionOffset++, vtableOffset);
+ // Setter:
+ if (!atd->bReadOnly) {
+ (s++)->fn = code + writetoexecdiff;
+ code = generateCodeSnippet(
+ code, functionOffset++, vtableOffset);
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ (s++)->fn = code + writetoexecdiff;
+ code = generateCodeSnippet(code, functionOffset++, vtableOffset);
+ break;
+ default:
+ assert(false);
+ }
+ TYPELIB_DANGER_RELEASE(td);
+ }
+ return code;
+}
+
+void bridges::cpp_uno::shared::VtableFactory::flushCode(
+ unsigned char const * begin, unsigned char const * end)
+{
+#if !defined ANDROID && !defined MACOSX
+ static void (*clear_cache)(unsigned char const *, unsigned char const *)
+ = (void (*)(unsigned char const *, unsigned char const *)) dlsym(
+ RTLD_DEFAULT, "__clear_cache");
+ (*clear_cache)(begin, end);
+#else
+ // GCC clarified with
+ // <http://gcc.gnu.org/git/?p=gcc.git;a=commit;h=a90b0cdd444f6dde1084a439862cf507f6d3b2ae>
+ // "extend.texi (__clear_cache): Correct signature" that __builtin___clear_cache takes void*
+ // parameters, while Clang uses char* ever since
+ // <https://github.com/llvm/llvm-project/commit/c491a8d4577052bc6b3b4c72a7db6a7cfcbc2ed0> "Add
+ // support for __builtin___clear_cache in Clang" (TODO: see
+ // <https://bugs.llvm.org/show_bug.cgi?id=48489> "__builtin___clear_cache() has a different
+ // prototype than GCC"; once fixed for our Clang baseline, we can drop the reinterpret_casts):
+ __builtin___clear_cache(
+ reinterpret_cast<char *>(const_cast<unsigned char *>(begin)),
+ reinterpret_cast<char *>(const_cast<unsigned char *>(end)));
+#endif
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_aarch64/uno2cpp.cxx b/bridges/source/cpp_uno/gcc3_linux_aarch64/uno2cpp.cxx
new file mode 100644
index 000000000..57beb6dfa
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_aarch64/uno2cpp.cxx
@@ -0,0 +1,519 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+#include <cstring>
+#include <exception>
+#include <typeinfo>
+
+#include <bridge.hxx>
+#include <types.hxx>
+#include <unointerfaceproxy.hxx>
+#include <vtables.hxx>
+#include <com/sun/star/uno/Exception.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/genfunc.hxx>
+#include <rtl/textenc.h>
+#include <rtl/ustring.hxx>
+#include <sal/alloca.h>
+#include <sal/types.h>
+#include <typelib/typeclass.h>
+#include <typelib/typedescription.h>
+#include <uno/any2.h>
+#include <uno/data.h>
+
+#include "abi.hxx"
+#include "callvirtualfunction.hxx"
+
+namespace {
+
+void pushArgument(
+#ifdef MACOSX
+ typelib_TypeClass typeclass,
+ sal_Int32 * const subsp,
+#endif
+ unsigned long value, unsigned long * const stack, sal_Int32 * const sp,
+ unsigned long * const regs, sal_Int32 * const nregs)
+{
+#ifdef MACOSX
+ if (*nregs != 8)
+ {
+ regs[(*nregs)++] = value;
+ }
+ else
+ {
+ switch (typeclass) {
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ *reinterpret_cast<uint8_t*>(reinterpret_cast<uintptr_t>(stack + *sp) + *subsp) = value;
+ (*subsp) += 1;
+ if (*subsp == 8)
+ {
+ (*sp)++;
+ *subsp = 0;
+ }
+ break;
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ case typelib_TypeClass_CHAR:
+ *subsp = (*subsp + 1) & ~0x1;
+ if (*subsp == 8)
+ {
+ (*sp)++;
+ *subsp = 0;
+ }
+ *reinterpret_cast<uint16_t*>(reinterpret_cast<uintptr_t>(stack + *sp) + *subsp) = value;
+ (*subsp) += 2;
+ if (*subsp == 8)
+ {
+ (*sp)++;
+ *subsp = 0;
+ }
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_FLOAT:
+ *subsp = (*subsp + 3) & ~0x3;
+ if (*subsp == 8)
+ {
+ (*sp)++;
+ *subsp = 0;
+ }
+ *reinterpret_cast<uint32_t*>(reinterpret_cast<uintptr_t>(stack + *sp) + *subsp) = value;
+ (*subsp) += 4;
+ if (*subsp == 8)
+ {
+ (*sp)++;
+ *subsp = 0;
+ }
+ break;
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ default:
+ if (*subsp > 0)
+ {
+ (*sp)++;
+ *subsp = 0;
+ }
+ stack[*sp] = value;
+ (*sp)++;
+ break;
+ }
+ }
+#else
+ (*nregs != 8 ? regs[(*nregs)++] : stack[(*sp)++]) = value;
+#endif
+}
+
+void call(
+ bridges::cpp_uno::shared::UnoInterfaceProxy * proxy,
+ bridges::cpp_uno::shared::VtableSlot slot,
+ typelib_TypeDescriptionReference * returnType, sal_Int32 count,
+ typelib_MethodParameter * parameters, void * returnValue, void ** arguments,
+ uno_Any ** exception)
+{
+ typelib_TypeDescription * rtd = nullptr;
+ TYPELIB_DANGER_GET(&rtd, returnType);
+ abi_aarch64::ReturnKind retKind = abi_aarch64::getReturnKind(rtd);
+ bool retConv = bridges::cpp_uno::shared::relatesToInterfaceType(rtd);
+ void * ret = retConv ? alloca(rtd->nSize) : returnValue;
+ unsigned long ** thisPtr
+ = reinterpret_cast<unsigned long **>(proxy->getCppI()) + slot.offset;
+ unsigned long * stack = static_cast<unsigned long *>(
+ alloca(count * sizeof (unsigned long)));
+ sal_Int32 sp = 0;
+#ifdef MACOSX
+ sal_Int32 subsp = 0;
+#endif
+ unsigned long gpr[8];
+ sal_Int32 ngpr = 0;
+ unsigned long fpr[8];
+ sal_Int32 nfpr = 0;
+ gpr[ngpr++] = reinterpret_cast<unsigned long>(thisPtr);
+ void ** cppArgs = static_cast<void **>(alloca(count * sizeof (void *)));
+ typelib_TypeDescription ** ptds =
+ static_cast<typelib_TypeDescription **>(
+ alloca(count * sizeof (typelib_TypeDescription *)));
+ for (sal_Int32 i = 0; i != count; ++i) {
+ if (!parameters[i].bOut &&
+ bridges::cpp_uno::shared::isSimpleType(parameters[i].pTypeRef))
+ {
+ cppArgs[i] = nullptr;
+ switch (parameters[i].pTypeRef->eTypeClass) {
+ case typelib_TypeClass_BOOLEAN:
+ pushArgument(
+#ifdef MACOSX
+ parameters[i].pTypeRef->eTypeClass, &subsp,
+#endif
+ static_cast<unsigned long>(*static_cast<sal_Bool *>(arguments[i])), stack, &sp,
+ gpr, &ngpr);
+ break;
+ case typelib_TypeClass_BYTE:
+ pushArgument(
+#ifdef MACOSX
+ parameters[i].pTypeRef->eTypeClass, &subsp,
+#endif
+ *static_cast<sal_Int8 *>(arguments[i]), stack, &sp, gpr,
+ &ngpr);
+ break;
+ case typelib_TypeClass_SHORT:
+ pushArgument(
+#ifdef MACOSX
+ parameters[i].pTypeRef->eTypeClass, &subsp,
+#endif
+ *static_cast<sal_Int16 *>(arguments[i]), stack, &sp, gpr,
+ &ngpr);
+ break;
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ pushArgument(
+#ifdef MACOSX
+ parameters[i].pTypeRef->eTypeClass, &subsp,
+#endif
+ *static_cast<sal_uInt16 *>(arguments[i]), stack, &sp, gpr,
+ &ngpr);
+ break;
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_ENUM:
+ pushArgument(
+#ifdef MACOSX
+ parameters[i].pTypeRef->eTypeClass, &subsp,
+#endif
+ *static_cast<sal_Int32 *>(arguments[i]), stack, &sp, gpr,
+ &ngpr);
+ break;
+ case typelib_TypeClass_UNSIGNED_LONG:
+ pushArgument(
+#ifdef MACOSX
+ parameters[i].pTypeRef->eTypeClass, &subsp,
+#endif
+ *static_cast<sal_uInt32 *>(arguments[i]), stack, &sp, gpr,
+ &ngpr);
+ break;
+ case typelib_TypeClass_HYPER:
+ pushArgument(
+#ifdef MACOSX
+ parameters[i].pTypeRef->eTypeClass, &subsp,
+#endif
+ *static_cast<sal_Int64 *>(arguments[i]), stack, &sp, gpr,
+ &ngpr);
+ break;
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ pushArgument(
+#ifdef MACOSX
+ parameters[i].pTypeRef->eTypeClass, &subsp,
+#endif
+ *static_cast<sal_uInt64 *>(arguments[i]), stack, &sp, gpr,
+ &ngpr);
+ break;
+ case typelib_TypeClass_FLOAT:
+ pushArgument(
+#ifdef MACOSX
+ parameters[i].pTypeRef->eTypeClass, &subsp,
+#endif
+ *static_cast<unsigned int *>(arguments[i]), stack, &sp, fpr,
+ &nfpr);
+ break;
+ case typelib_TypeClass_DOUBLE:
+ pushArgument(
+#ifdef MACOSX
+ parameters[i].pTypeRef->eTypeClass, &subsp,
+#endif
+ *static_cast<unsigned long *>(arguments[i]), stack, &sp,
+ fpr, &nfpr);
+ break;
+ case typelib_TypeClass_CHAR:
+ pushArgument(
+#ifdef MACOSX
+ parameters[i].pTypeRef->eTypeClass, &subsp,
+#endif
+ *static_cast<sal_Unicode *>(arguments[i]), stack, &sp, gpr,
+ &ngpr);
+ break;
+ default:
+ assert(false);
+ }
+ } else {
+ typelib_TypeDescription * ptd = nullptr;
+ TYPELIB_DANGER_GET(&ptd, parameters[i].pTypeRef);
+ if (!parameters[i].bIn) {
+ cppArgs[i] = alloca(ptd->nSize);
+ uno_constructData(cppArgs[i], ptd);
+ ptds[i] = ptd;
+ pushArgument(
+#ifdef MACOSX
+ typelib_TypeClass_HYPER, &subsp,
+#endif
+ reinterpret_cast<unsigned long>(cppArgs[i]), stack, &sp,
+ gpr, &ngpr);
+ } else if (bridges::cpp_uno::shared::relatesToInterfaceType(ptd)) {
+ cppArgs[i] = alloca(ptd->nSize);
+ uno_copyAndConvertData(
+ cppArgs[i], arguments[i], ptd,
+ proxy->getBridge()->getUno2Cpp());
+ ptds[i] = ptd;
+ pushArgument(
+#ifdef MACOSX
+ typelib_TypeClass_HYPER, &subsp,
+#endif
+ reinterpret_cast<unsigned long>(cppArgs[i]), stack, &sp,
+ gpr, &ngpr);
+ } else {
+ cppArgs[i] = nullptr;
+ pushArgument(
+#ifdef MACOSX
+ typelib_TypeClass_HYPER, &subsp,
+#endif
+ reinterpret_cast<unsigned long>(arguments[i]), stack, &sp,
+ gpr, &ngpr);
+ TYPELIB_DANGER_RELEASE(ptd);
+ }
+ }
+ }
+ try {
+ try {
+ callVirtualFunction(
+ (*thisPtr)[slot.index], gpr, fpr, stack, sp, ret);
+ } catch (css::uno::Exception &) {
+ throw;
+ } catch (std::exception & e) {
+ throw css::uno::RuntimeException(
+ "C++ code threw "
+ + OStringToOUString(typeid(e).name(), RTL_TEXTENCODING_UTF8)
+ + ": " + OStringToOUString(e.what(), RTL_TEXTENCODING_UTF8));
+ } catch (...) {
+ throw css::uno::RuntimeException(
+ "C++ code threw unknown exception");
+ }
+ } catch (css::uno::Exception &) {
+ __cxxabiv1::__cxa_exception * header = reinterpret_cast<__cxxabiv1::__cxa_eh_globals *>(
+ __cxxabiv1::__cxa_get_globals())->caughtExceptions;
+#if !defined MACOSX && defined _LIBCPPABI_VERSION // detect libc++abi
+ // Very bad HACK to find out whether we run against a libcxxabi that has a new
+ // __cxa_exception::reserved member at the start, introduced with LLVM 10
+ // <https://github.com/llvm/llvm-project/commit/674ec1eb16678b8addc02a4b0534ab383d22fa77>
+ // "[libcxxabi] Insert padding in __cxa_exception struct for compatibility". The layout of
+ // the start of __cxa_exception is
+ //
+ // [8 byte void *reserve]
+ // 8 byte size_t referenceCount
+ //
+ // where the (bad, hacky) assumption is that reserve (if present) is null
+ // (__cxa_allocate_exception in at least LLVM 11 zero-fills the object, and nothing actively
+ // sets reserve) while referenceCount is non-null (__cxa_throw sets it to 1, and
+ // __cxa_decrement_exception_refcount destroys the exception as soon as it drops to 0; for a
+ // __cxa_dependent_exception, the referenceCount member is rather
+ //
+ // 8 byte void* primaryException
+ //
+ // but which also will always be set to a non-null value in
+ // __cxa_rethrow_primary_exception). As described in the definition of __cxa_exception
+ // (bridges/source/cpp_uno/gcc3_linux_aarch64/abi.hxx), this hack (together with the
+ // "#ifdef MACOSX" there) can be dropped once we can be sure that we only run against new
+ // libcxxabi that has the reserve member:
+ if (*reinterpret_cast<void **>(header) == nullptr) {
+ header = reinterpret_cast<__cxxabiv1::__cxa_exception*>(
+ reinterpret_cast<void **>(header) + 1);
+ }
+#endif
+ abi_aarch64::mapException(
+ header,
+ __cxxabiv1::__cxa_current_exception_type(), *exception,
+ proxy->getBridge()->getCpp2Uno());
+ for (sal_Int32 i = 0; i != count; ++i) {
+ if (cppArgs[i] != nullptr) {
+ uno_destructData(
+ cppArgs[i], ptds[i],
+ reinterpret_cast<uno_ReleaseFunc>(css::uno::cpp_release));
+ TYPELIB_DANGER_RELEASE(ptds[i]);
+ }
+ }
+ TYPELIB_DANGER_RELEASE(rtd);
+ return;
+ }
+ *exception = nullptr;
+ for (sal_Int32 i = 0; i != count; ++i) {
+ if (cppArgs[i] != nullptr) {
+ if (parameters[i].bOut) {
+ if (parameters[i].bIn) {
+ uno_destructData(arguments[i], ptds[i], nullptr);
+ }
+ uno_copyAndConvertData(
+ arguments[i], cppArgs[i], ptds[i],
+ proxy->getBridge()->getCpp2Uno());
+ }
+ uno_destructData(
+ cppArgs[i], ptds[i],
+ reinterpret_cast<uno_ReleaseFunc>(css::uno::cpp_release));
+ TYPELIB_DANGER_RELEASE(ptds[i]);
+ }
+ }
+ switch (retKind) {
+ case abi_aarch64::RETURN_KIND_REG:
+ switch (rtd->eTypeClass) {
+ case typelib_TypeClass_VOID:
+ break;
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_STRUCT:
+ std::memcpy(ret, gpr, rtd->nSize);
+ break;
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ std::memcpy(ret, fpr, rtd->nSize);
+ break;
+ default:
+ assert(false);
+ }
+ break;
+ case abi_aarch64::RETURN_KIND_HFA_FLOAT:
+ switch (rtd->nSize) {
+ case 16:
+ std::memcpy(static_cast<char *>(ret) + 12, fpr + 3, 4);
+ [[fallthrough]];
+ case 12:
+ std::memcpy(static_cast<char *>(ret) + 8, fpr + 2, 4);
+ [[fallthrough]];
+ case 8:
+ std::memcpy(static_cast<char *>(ret) + 4, fpr + 1, 4);
+ [[fallthrough]];
+ case 4:
+ std::memcpy(ret, fpr, 4);
+ break;
+ default:
+ assert(false);
+ }
+ break;
+ case abi_aarch64::RETURN_KIND_HFA_DOUBLE:
+ std::memcpy(ret, fpr, rtd->nSize);
+ break;
+ case abi_aarch64::RETURN_KIND_INDIRECT:
+ break;
+ }
+ if (retConv) {
+ uno_copyAndConvertData(
+ returnValue, ret, rtd, proxy->getBridge()->getCpp2Uno());
+ uno_destructData(
+ ret, rtd, reinterpret_cast<uno_ReleaseFunc>(css::uno::cpp_release));
+ }
+ TYPELIB_DANGER_RELEASE(rtd);
+}
+
+}
+
+namespace bridges::cpp_uno::shared {
+
+void unoInterfaceProxyDispatch(
+ uno_Interface * pUnoI, typelib_TypeDescription const * pMemberDescr,
+ void * pReturn, void ** pArgs, uno_Any ** ppException)
+{
+ UnoInterfaceProxy * proxy = static_cast<UnoInterfaceProxy *>(pUnoI);
+ switch (pMemberDescr->eTypeClass) {
+ case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+ {
+ typelib_InterfaceAttributeTypeDescription const * atd
+ = reinterpret_cast<
+ typelib_InterfaceAttributeTypeDescription const *>(
+ pMemberDescr);
+ VtableSlot slot(getVtableSlot(atd));
+ if (pReturn != nullptr) { // getter
+ call(
+ proxy, slot, atd->pAttributeTypeRef, 0, nullptr, pReturn, pArgs,
+ ppException);
+ } else { // setter
+ typelib_MethodParameter param = {
+ nullptr, atd->pAttributeTypeRef, true, false };
+ typelib_TypeDescriptionReference * rtd = nullptr;
+ typelib_typedescriptionreference_new(
+ &rtd, typelib_TypeClass_VOID, OUString("void").pData);
+ slot.index += 1;
+ call(proxy, slot, rtd, 1, &param, pReturn, pArgs, ppException);
+ typelib_typedescriptionreference_release(rtd);
+ }
+ break;
+ }
+ case typelib_TypeClass_INTERFACE_METHOD:
+ {
+ typelib_InterfaceMethodTypeDescription const * mtd
+ = reinterpret_cast<
+ typelib_InterfaceMethodTypeDescription const *>(
+ pMemberDescr);
+ VtableSlot slot(getVtableSlot(mtd));
+ switch (slot.index) {
+ case 1:
+ pUnoI->acquire(pUnoI);
+ *ppException = nullptr;
+ break;
+ case 2:
+ pUnoI->release(pUnoI);
+ *ppException = nullptr;
+ break;
+ case 0:
+ {
+ typelib_TypeDescription * td = nullptr;
+ TYPELIB_DANGER_GET(
+ &td,
+ (static_cast<css::uno::Type *>(pArgs[0])
+ ->getTypeLibType()));
+ if (td != nullptr) {
+ uno_Interface * ifc = nullptr;
+ proxy->pBridge->getUnoEnv()->getRegisteredInterface(
+ proxy->pBridge->getUnoEnv(),
+ reinterpret_cast<void **>(&ifc), proxy->oid.pData,
+ reinterpret_cast<
+ typelib_InterfaceTypeDescription *>(td));
+ if (ifc != nullptr) {
+ uno_any_construct(
+ static_cast<uno_Any *>(pReturn), &ifc, td,
+ nullptr);
+ ifc->release(ifc);
+ TYPELIB_DANGER_RELEASE(td);
+ *ppException = nullptr;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE(td);
+ }
+ }
+ [[fallthrough]];
+ default:
+ call(
+ proxy, slot, mtd->pReturnTypeRef, mtd->nParams,
+ mtd->pParams, pReturn, pArgs, ppException);
+ break;
+ }
+ break;
+ }
+ default:
+ assert(false);
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_aarch64/vtablecall.hxx b/bridges/source/cpp_uno/gcc3_linux_aarch64/vtablecall.hxx
new file mode 100644
index 000000000..6ec92687c
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_aarch64/vtablecall.hxx
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <sal/types.h>
+
+extern "C" {
+void vtableCall(sal_Int32 functionIndex, sal_Int32 vtableOffset, unsigned long* gpr,
+ unsigned long* fpr, unsigned long* stack, void* indirectRet);
+
+void vtableSlotCall();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/bridges/source/cpp_uno/gcc3_linux_aarch64/vtableslotcall.s b/bridges/source/cpp_uno/gcc3_linux_aarch64/vtableslotcall.s
new file mode 100644
index 000000000..60bdb4c9c
--- /dev/null
+++ b/bridges/source/cpp_uno/gcc3_linux_aarch64/vtableslotcall.s
@@ -0,0 +1,83 @@
+/* -*- tab-width: 4; indent-tabs-mode: nil; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+ .arch armv8-a
+ .text
+ .align 2
+#ifndef __APPLE__
+ .global vtableSlotCall
+ .hidden vtableSlotCall
+ .type vtableSlotCall, %function
+vtableSlotCall:
+#else
+ .global _vtableSlotCall
+_vtableSlotCall:
+#endif
+ .cfi_startproc
+ stp x29, x30, [sp, -192]!
+ .cfi_def_cfa_offset 192
+ .cfi_offset 29, -192
+ .cfi_offset 30, -184
+ add x11, sp, 192
+ mov x29, sp
+ stp x19, x20, [sp, 16]
+ .cfi_offset 19, -176
+ .cfi_offset 20, -168
+ add x20, sp, 128
+ add x19, sp, 64
+ stp x11, x11, [sp, 32]
+ str x11, [sp, 48]
+ stp wzr, wzr, [sp, 56]
+ stp x0, x1, [sp, 64]
+ mov w0, w9
+ mov w1, w10
+ stp x2, x3, [sp, 80]
+ mov x3, x20
+ mov x2, x19
+ stp x4, x5, [sp, 96]
+ mov x5, x8
+ mov x4, x11
+ stp x6, x7, [sp, 112]
+ stp d0, d1, [sp, 128]
+ stp d2, d3, [sp, 144]
+ stp d4, d5, [sp, 160]
+ stp d6, d7, [sp, 176]
+#ifndef __APPLE__
+ bl vtableCall
+#else
+ bl _vtableCall
+#endif
+ ldp x0, x1, [x19]
+ ldp d0, d1, [x20]
+ ldp d2, d3, [x20, #16]
+ ldp x19, x20, [sp, 16]
+ ldp x29, x30, [sp], 192
+ .cfi_restore 30
+ .cfi_restore 29
+ .cfi_restore 19
+ .cfi_restore 20
+ .cfi_def_cfa_offset 0
+ ret
+ .cfi_endproc
+#ifndef __APPLE__
+ .size vtableSlotCall, .-vtableSlotCall
+ .section .note.GNU-stack, "", @progbits
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab */