diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /bridges/source/cpp_uno/gcc3_linux_aarch64/cpp2uno.cxx | |
parent | Initial commit. (diff) | |
download | libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'bridges/source/cpp_uno/gcc3_linux_aarch64/cpp2uno.cxx')
-rw-r--r-- | bridges/source/cpp_uno/gcc3_linux_aarch64/cpp2uno.cxx | 599 |
1 files changed, 599 insertions, 0 deletions
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: */ |