1
0
Fork 0
libreoffice/bridges/source/cpp_uno/gcc3_linux_aarch64/uno2cpp.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

519 lines
19 KiB
C++

/* -*- 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: */