diff options
Diffstat (limited to 'bridges/source/cpp_uno/gcc3_linux_aarch64')
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, ¶m, 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, ¶m, 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 */ |