From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- bridges/source/cpp_uno/msvc_win32_arm64/abi.cxx | 158 ++++++++ bridges/source/cpp_uno/msvc_win32_arm64/abi.hxx | 34 ++ .../cpp_uno/msvc_win32_arm64/callvirtualfunction.S | 72 ++++ .../source/cpp_uno/msvc_win32_arm64/cpp2uno.cxx | 432 +++++++++++++++++++++ bridges/source/cpp_uno/msvc_win32_arm64/except.cxx | 234 +++++++++++ .../source/cpp_uno/msvc_win32_arm64/uno2cpp.cxx | 341 ++++++++++++++++ .../cpp_uno/msvc_win32_arm64/vtableslotcall.S | 72 ++++ 7 files changed, 1343 insertions(+) create mode 100644 bridges/source/cpp_uno/msvc_win32_arm64/abi.cxx create mode 100644 bridges/source/cpp_uno/msvc_win32_arm64/abi.hxx create mode 100644 bridges/source/cpp_uno/msvc_win32_arm64/callvirtualfunction.S create mode 100644 bridges/source/cpp_uno/msvc_win32_arm64/cpp2uno.cxx create mode 100644 bridges/source/cpp_uno/msvc_win32_arm64/except.cxx create mode 100644 bridges/source/cpp_uno/msvc_win32_arm64/uno2cpp.cxx create mode 100644 bridges/source/cpp_uno/msvc_win32_arm64/vtableslotcall.S (limited to 'bridges/source/cpp_uno/msvc_win32_arm64') diff --git a/bridges/source/cpp_uno/msvc_win32_arm64/abi.cxx b/bridges/source/cpp_uno/msvc_win32_arm64/abi.cxx new file mode 100644 index 000000000..c88873143 --- /dev/null +++ b/bridges/source/cpp_uno/msvc_win32_arm64/abi.cxx @@ -0,0 +1,158 @@ +/* -*- 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 +#include + +#include + +#include "abi.hxx" + +enum StructKind +{ + STRUCT_KIND_EMPTY, + STRUCT_KIND_FLOAT, + STRUCT_KIND_DOUBLE, + STRUCT_KIND_POD, + STRUCT_KIND_DTOR +}; + +static StructKind getStructKind(typelib_CompoundTypeDescription const* type) +{ + StructKind k = type->pBaseTypeDescription == 0 ? 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 = 0; + TYPELIB_DANGER_GET(&td, type->ppTypeRefs[i]); + k2 = getStructKind(reinterpret_cast(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; +} + +ReturnKind getReturnKind(typelib_TypeDescription const* type) +{ + switch (type->eTypeClass) + { + default: + assert(false); + [[fallthrough]]; + 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(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/msvc_win32_arm64/abi.hxx b/bridges/source/cpp_uno/msvc_win32_arm64/abi.hxx new file mode 100644 index 000000000..38a61161c --- /dev/null +++ b/bridges/source/cpp_uno/msvc_win32_arm64/abi.hxx @@ -0,0 +1,34 @@ +/* -*- 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 + +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/msvc_win32_arm64/callvirtualfunction.S b/bridges/source/cpp_uno/msvc_win32_arm64/callvirtualfunction.S new file mode 100644 index 000000000..e03bff1d2 --- /dev/null +++ b/bridges/source/cpp_uno/msvc_win32_arm64/callvirtualfunction.S @@ -0,0 +1,72 @@ +/* -*- 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/. + */ + + OPT 2 // disable listing +// macros to add unwind information +#include "ksarm64.h" + OPT 1 // re-enable listing + + EXPORT callVirtualFunction + + TEXTAREA, ALIGN=8 + +/* + extern void callVirtualFunction + + x0 stack + x1 frame + x2 function + x3 return +*/ + + NESTED_ENTRY callVirtualFunction_fake + + // for unwind information, Windows has to store fp and lr + PROLOG_SAVE_REG_PAIR x29, x30, #-32! + + ALTERNATE_ENTRY callVirtualFunction + + // use a stack frame allocated by our caller + stp x29, x30, [x1] + mov x29, x1 + mov sp, x0 + + mov x9, x2 // function + mov x8, x3 // complex return + str x3, [x29, #16] // save rvalue + + // load the core argument passing registers + ldp x0, x1, [sp, #0] + ldp x2, x3, [sp, #16] + ldp x4, x5, [sp, #32] + ldp x6, x7, [sp, #48] + + ldp d0, d1, [sp, #64] + ldp d2, d3, [sp, #80] + ldp d4, d5, [sp, #96] + ldp d6, d7, [sp, #112] + + blr x9 // call + + ldr x3, [x29, #16] // reload rvalue + + // partially deconstruct the stack frame + mov sp, x29 + ldp x29, x30, [x29] + + // save the simple return values + stp x0, x1, [sp, #0] + stp d0, d1, [sp, #64] + stp d2, d3, [sp, #80] + + NESTED_END callVirtualFunction_fake + + END + +/* vim:set shiftwidth=4 softtabstop=4 expandtab */ diff --git a/bridges/source/cpp_uno/msvc_win32_arm64/cpp2uno.cxx b/bridges/source/cpp_uno/msvc_win32_arm64/cpp2uno.cxx new file mode 100644 index 000000000..cfefa60e7 --- /dev/null +++ b/bridges/source/cpp_uno/msvc_win32_arm64/cpp2uno.cxx @@ -0,0 +1,432 @@ +/* -*- 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 + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "abi.hxx" + +extern "C" void vtableSlotCall(); + +using namespace ::com::sun::star; + +namespace +{ +void call(bridges::cpp_uno::shared::CppInterfaceProxy* proxy, + uno::TypeDescription const& description, typelib_TypeDescriptionReference* returnType, + sal_Int32 count, typelib_MethodParameter* parameters, sal_uInt64* gpr, sal_uInt64* fpr, + sal_uInt64* stack, void* indirectRet) +{ + typelib_TypeDescription* rtd = 0; + if (returnType != 0) + TYPELIB_DANGER_GET(&rtd, returnType); + + ReturnKind retKind = rtd == 0 ? RETURN_KIND_REG : getReturnKind(rtd); + bool retConv = rtd != 0 && bridges::cpp_uno::shared::relatesToInterfaceType(rtd); + + void* retin = retKind == RETURN_KIND_INDIRECT && !retConv ? indirectRet + : rtd == 0 ? 0 : alloca(rtd->nSize); + void** args = static_cast(alloca(count * sizeof(void*))); + void** cppArgs = static_cast(alloca(count * sizeof(void*))); + typelib_TypeDescription** argtds + = static_cast(alloca(count * sizeof(typelib_TypeDescription*))); + + sal_Int32 ngpr = 1; + sal_Int32 nfpr = 0; + sal_Int32 sp = 0; + 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) + { + 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; + default: + assert(false); + } + argtds[i] = 0; + } + else + { + cppArgs[i] = reinterpret_cast(ngpr == 8 ? stack[sp++] : gpr[ngpr++]); + typelib_TypeDescription* ptd = 0; + 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] = 0; + TYPELIB_DANGER_RELEASE(ptd); + } + } + } + + uno_Any exc; + uno_Any* pexc = &exc; + proxy->getUnoI()->pDispatcher(proxy->getUnoI(), description.get(), retin, args, &pexc); + if (pexc != 0) + { + for (sal_Int32 i = 0; i != count; ++i) + { + if (argtds[i] == 0) + continue; + if (parameters[i].bIn) + uno_destructData(args[i], argtds[i], 0); + TYPELIB_DANGER_RELEASE(argtds[i]); + } + if (rtd != 0) + TYPELIB_DANGER_RELEASE(rtd); + assert(pexc == &exc); + msvc_raiseException(&exc, proxy->getBridge()->getUno2Cpp()); + } + + for (sal_Int32 i = 0; i != count; ++i) + { + if (argtds[i] != 0) + { + if (parameters[i].bOut) + { + uno_destructData(cppArgs[i], argtds[i], + reinterpret_cast(uno::cpp_release)); + uno_copyAndConvertData(cppArgs[i], args[i], argtds[i], + proxy->getBridge()->getUno2Cpp()); + } + uno_destructData(args[i], argtds[i], 0); + TYPELIB_DANGER_RELEASE(argtds[i]); + } + } + + void* retout = 0; // avoid false -Werror=maybe-uninitialized + switch (retKind) + { + case RETURN_KIND_REG: + switch (rtd == 0 ? typelib_TypeClass_VOID : 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: + 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 RETURN_KIND_HFA_FLOAT: + assert(rtd != 0); + switch (rtd->nSize) + { + case 16: + std::memcpy(fpr + 3, static_cast(retin) + 12, 4); + [[fallthrough]]; + case 12: + std::memcpy(fpr + 2, static_cast(retin) + 8, 4); + [[fallthrough]]; + case 8: + std::memcpy(fpr + 1, static_cast(retin) + 4, 4); + [[fallthrough]]; + case 4: + std::memcpy(fpr, retin, 4); + break; + default: + assert(false); + } + assert(!retConv); + break; + case RETURN_KIND_HFA_DOUBLE: + assert(rtd != 0); + std::memcpy(fpr, retin, rtd->nSize); + assert(!retConv); + break; + case RETURN_KIND_INDIRECT: + retout = indirectRet; + break; + } + + if (retConv) + { + uno_copyAndConvertData(retout, retin, rtd, proxy->getBridge()->getUno2Cpp()); + uno_destructData(retin, rtd, 0); + } + + if (rtd != 0) + TYPELIB_DANGER_RELEASE(rtd); +} + +extern "C" void vtableCall(sal_Int32 functionIndex, sal_Int32 vtableOffset, sal_uInt64* gpr, + sal_uInt64* fpr, sal_uInt64* stack, void* indirectRet) +{ + bridges::cpp_uno::shared::CppInterfaceProxy* proxy + = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( + reinterpret_cast(gpr[0]) - vtableOffset); + typelib_InterfaceTypeDescription* pInterfaceTD = proxy->getTypeDescr(); + assert(functionIndex < pInterfaceTD->nMapFunctionIndexToMemberIndex); + sal_Int32 nMemberPos = pInterfaceTD->pMapFunctionIndexToMemberIndex[functionIndex]; + assert(nMemberPos < pInterfaceTD->nAllMembers); + uno::TypeDescription aMemberDescr(pInterfaceTD->ppAllMembers[nMemberPos]); + + switch (aMemberDescr.get()->eTypeClass) + { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + { + typelib_TypeDescriptionReference* pAttrTypeRef + = reinterpret_cast(aMemberDescr.get()) + ->pAttributeTypeRef; + + if (pInterfaceTD->pMapMemberIndexToFunctionIndex[nMemberPos] == functionIndex) + { + // Getter: + call(proxy, aMemberDescr, pAttrTypeRef, 0, 0, gpr, fpr, stack, indirectRet); + } + else + { + // Setter: + typelib_MethodParameter param = { 0, pAttrTypeRef, true, false }; + call(proxy, aMemberDescr, 0, 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(gpr[1])->getTypeLibType())); + if (td != 0 && td->eTypeClass == typelib_TypeClass_INTERFACE) + { + uno::XInterface* ifc = nullptr; + proxy->getBridge()->getCppEnv()->getRegisteredInterface( + proxy->getBridge()->getCppEnv(), reinterpret_cast(&ifc), + proxy->getOid().pData, + reinterpret_cast(td)); + if (ifc != 0) + { + uno_any_construct(reinterpret_cast(indirectRet), &ifc, td, + reinterpret_cast(uno::cpp_acquire)); + ifc->release(); + TYPELIB_DANGER_RELEASE(td); + break; + } + TYPELIB_DANGER_RELEASE(td); + } + } + [[fallthrough]]; + default: + typelib_InterfaceMethodTypeDescription* pMethodTD + = reinterpret_cast( + aMemberDescr.get()); + call(proxy, aMemberDescr, pMethodTD->pReturnTypeRef, pMethodTD->nParams, + pMethodTD->pParams, gpr, fpr, stack, indirectRet); + } + break; + default: + assert(false); + } +} + +std::size_t const codeSnippetSize = 8 * 4; + +unsigned char* GenerateVTableSlotTrampoline(unsigned char* code, sal_Int32 functionIndex, + sal_Int32 vtableOffset) +{ + // movz x9, + reinterpret_cast(code)[0] = 0xD2800009 | ((functionIndex & 0xFFFF) << 5); + // movk x9, , LSL #16 + reinterpret_cast(code)[1] = 0xF2A00009 | ((functionIndex >> 16) << 5); + // movz x10, + reinterpret_cast(code)[2] = 0xD280000A | ((vtableOffset & 0xFFFF) << 5); + // movk x10, , LSL #16 + reinterpret_cast(code)[3] = 0xF2A0000A | ((vtableOffset >> 16) << 5); + // ldr x11, +2*4 + reinterpret_cast(code)[4] = 0x5800004B; + // br x11 + reinterpret_cast(code)[5] = 0xD61F0160; + reinterpret_cast(code)[3] = reinterpret_cast(&vtableSlotCall); + return code + codeSnippetSize; +} +} + +namespace bridges::cpp_uno::shared +{ +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(block) + 1; +} + +std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(sal_Int32 slotCount) +{ + return (slotCount + 1) * 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*) +{ + struct Rtti + { + sal_Int32 n0, n1, n2; + type_info* rtti; + Rtti() + : n0(0) + , n1(0) + , n2(0) + , rtti(RTTInfos::get("com.sun.star.uno.XInterface")) + { + } + }; + static Rtti rtti; + + Slot* slots = mapBlockToVtable(block); + slots[-1].fn = &rtti; + return slots + slotCount; +} + +unsigned char* VtableFactory::addLocalFunctions(VtableFactory::Slot** slots, unsigned char* code, + typelib_InterfaceTypeDescription const* type, + sal_Int32 functionOffset, sal_Int32 functionCount, + sal_Int32 vtableOffset) +{ + (*slots) -= functionCount; + VtableFactory::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 != 0); + switch (td->eTypeClass) + { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + { + typelib_InterfaceAttributeTypeDescription* atd + = reinterpret_cast(td); + // Getter: + (s++)->fn = code; + code = GenerateVTableSlotTrampoline(code, functionOffset++, vtableOffset); + // Setter: + if (!atd->bReadOnly) + { + (s++)->fn = code; + code = GenerateVTableSlotTrampoline(code, functionOffset++, vtableOffset); + } + break; + } + case typelib_TypeClass_INTERFACE_METHOD: + (s++)->fn = code; + code = GenerateVTableSlotTrampoline(code, functionOffset++, vtableOffset); + break; + default: + assert(false); + } + TYPELIB_DANGER_RELEASE(td); + } + return code; +} + +void VtableFactory::flushCode(unsigned char const* begin, unsigned char const* end) +{ + FlushInstructionCache(GetCurrentProcess(), begin, end - begin); +} + +} // namespace bridges::cpp_uno::shared + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/bridges/source/cpp_uno/msvc_win32_arm64/except.cxx b/bridges/source/cpp_uno/msvc_win32_arm64/except.cxx new file mode 100644 index 000000000..8cc380c5d --- /dev/null +++ b/bridges/source/cpp_uno/msvc_win32_arm64/except.cxx @@ -0,0 +1,234 @@ +/* -*- 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 + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#pragma pack(push, 8) + +using namespace ::com::sun::star; + +static void* __cdecl copyConstruct(void* pExcThis, void* pSource, + typelib_TypeDescription* pTD) noexcept +{ + ::uno_copyData(pExcThis, pSource, pTD, uno::cpp_acquire); + return pExcThis; +} + +static void* __cdecl destruct(void* pExcThis, typelib_TypeDescription* pTD) noexcept +{ + ::uno_destructData(pExcThis, pTD, uno::cpp_release); + return pExcThis; +} + +const int nCodeSnippetSize = 28; + +static void GenerateCopyConstructorTrampoline(unsigned char* target, + typelib_TypeDescription* pTD) noexcept +{ + // ldr x2, #12 + // ldr x3, #20 + // br x3 + // pTD + // ©Construct + static const char code[] = "\x62\x00\x00\x58\x83\x00\x00\x58\x60\x00\x1f\xd6"; + static_assert(sizeof(code) == 13); + static const unsigned int code_size = sizeof(code) - 1; + + memcpy(target, code, code_size); + *reinterpret_cast(target + code_size) = pTD; + *reinterpret_cast(target + code_size + 8) = ©Construct; +} + +static void GenerateDestructorTrampoline(unsigned char* target, + typelib_TypeDescription* pTD) noexcept +{ + // ldr x1, #12 + // ldr x2, #20 + // br x2 + // pTD + // &destruct + static const char code[] = "\x61\x00\x00\x58\x82\x00\x00\x58\x40\x00\x1f\xd6"; + static_assert(sizeof(code) == 13); + static const unsigned int code_size = sizeof(code) - 1; + + memcpy(target, code, code_size); + *reinterpret_cast(target + code_size) = pTD; + *reinterpret_cast(target + code_size + 8) = &destruct; +} + +ExceptionType::ExceptionType(unsigned char* pCode, sal_uInt64 pCodeBase, + typelib_TypeDescription* pTD) noexcept + : _n0(0) + , _n1(0) + , _n2(-1) + , _n3(0) + , _n4(pTD->nSize) + , exc_type_info(nullptr, "") +{ + // As _n0 is always initialized to zero, that means the + // hasvirtbase flag (see the ONTL catchabletype struct) is + // off, and thus the copyctor is of the ctor_ptr kind. + + int len; + type_info* pRTTI = RTTInfos::get(pTD->pTypeName, &len); + + memcpy(static_cast(&exc_type_info), static_cast(pRTTI), len); + _pTypeInfo = static_cast(reinterpret_cast(&exc_type_info) - pCodeBase); + GenerateCopyConstructorTrampoline(pCode, pTD); + + assert(pCodeBase <= reinterpret_cast(pCode) + && (reinterpret_cast(pCode) - pCodeBase < 0x100000000)); + _pCopyCtor = static_cast(reinterpret_cast(pCode) - pCodeBase); +} + +/* Rewrite of 32-Bit-Code to work under 64 Bit: +* To use the 32 Bit offset values in the ExceptionType we have to +* allocate a single allocation block and use it for all code and date +* all offsets inside this area are guaranteed to be in 32 bit address range. +* So we have to calc total memory allocation size for D-tor, C-Tors, +* ExceptionType and type_info. ExceptionType is allocated via placement new +* to locate everything inside our mem block. +* There is one caveat: Struct type_info is kept in +* a map and was referenced from class ExceptionType. Therefore type_info now +* is also member of ExceptionType and can be referenced via 32 bit offset. +*/ + +RaiseInfo::RaiseInfo(typelib_TypeDescription* pTD) noexcept + : _n0(0) + , _n2(0) + , _pTD(pTD) +{ + typelib_CompoundTypeDescription* pCompTD; + + // Count how many trampolines we need + int codeSize = nCodeSnippetSize; + + // Info count + int nLen = 0; + for (pCompTD = reinterpret_cast(pTD); pCompTD; + pCompTD = pCompTD->pBaseTypeDescription) + { + ++nLen; + codeSize += nCodeSnippetSize; + } + + // Array with size (4) and all _pTypeInfo (4*nLen) + int typeInfoArraySize = 4 + 4 * nLen; + + // 2.Pass: Get the total needed memory for class ExceptionType + // (with embedded type_info) and keep the sizes for each instance + // is stored in allocated int array + auto exceptionTypeSizeArray = std::make_unique(nLen); + + nLen = 0; + for (pCompTD = reinterpret_cast(pTD); pCompTD; + pCompTD = pCompTD->pBaseTypeDescription) + { + int typeInfoLen; + RTTInfos::get(pCompTD->aBase.pTypeName, &typeInfoLen); + // Mem has to be on 4-byte Boundary + if (typeInfoLen % 4 != 0) + { + int n = typeInfoLen / 4; + n++; + typeInfoLen = n * 4; + } + exceptionTypeSizeArray[nLen++] = typeInfoLen + sizeof(ExceptionType); + } + + // Total ExceptionType related mem + int excTypeAddLen = 0; + for (int i = 0; i < nLen; i++) + { + excTypeAddLen += exceptionTypeSizeArray[i]; + } + + // Allocate mem for code and all dynamic data in one chunk to guarantee + // 32 bit offsets + const int totalSize = codeSize + typeInfoArraySize + excTypeAddLen; + unsigned char* pCode = _code = static_cast(std::malloc(totalSize)); + int pCodeOffset = 0; + + // New base of types array, starts after Trampoline D-Tor / C-Tors + DWORD* types = reinterpret_cast(pCode + codeSize); + + // New base of ExceptionType array, starts after types array + unsigned char* etMem = pCode + codeSize + typeInfoArraySize; + int etMemOffset = 0; + + _codeBase = reinterpret_cast(pCode) + & ~static_cast(ExceptionInfos::allocationGranularity - 1); + + DWORD old_protect; + bool success = VirtualProtect(pCode, codeSize, PAGE_EXECUTE_READWRITE, &old_protect); + (void)success; + assert(success && "VirtualProtect() failed!"); + + ::typelib_typedescription_acquire(pTD); + + // Fill pCode with D-Tor code + GenerateDestructorTrampoline(pCode, pTD); + _pDtor = static_cast(reinterpret_cast(pCode) - _codeBase); + pCodeOffset += nCodeSnippetSize; + + // Info count accompanied by type info ptrs: type, base type, base base type, ... + // Keep offset of types_array + _types = static_cast(reinterpret_cast(types) - _codeBase); + // Fill types: (nLen, _offset to ExceptionType1, ...ExceptionType2, ...) + types[0] = nLen; + + int nPos = 1; + for (pCompTD = reinterpret_cast(pTD); pCompTD; + pCompTD = pCompTD->pBaseTypeDescription) + { + // Create instance in mem block with placement new + ExceptionType* et = new (etMem + etMemOffset) ExceptionType( + pCode + pCodeOffset, _codeBase, reinterpret_cast(pCompTD)); + + // Next trampoline entry offset + pCodeOffset += nCodeSnippetSize; + // Next ExceptionType placement offset + etMemOffset += exceptionTypeSizeArray[nPos - 1]; + + // Keep offset of addresses of ET for D-Tor call in ~RaiseInfo + types[nPos++] = static_cast(reinterpret_cast(et) - _codeBase); + } + // Final check: end of address calculation must be end of mem + assert(etMem + etMemOffset == pCode + totalSize); +} + +#pragma pack(pop) + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/bridges/source/cpp_uno/msvc_win32_arm64/uno2cpp.cxx b/bridges/source/cpp_uno/msvc_win32_arm64/uno2cpp.cxx new file mode 100644 index 000000000..a0c2adc6f --- /dev/null +++ b/bridges/source/cpp_uno/msvc_win32_arm64/uno2cpp.cxx @@ -0,0 +1,341 @@ +/* -*- 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 + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "abi.hxx" +#include + +namespace +{ +extern "C" void callVirtualFunction(sal_uInt64* stack, sal_uInt64* frame, sal_uInt64 function, + void* ret); + +void pushArgument(sal_uInt64 value, sal_uInt64* stack, sal_Int32& sp, sal_uInt64* regs, + sal_Int32& nregs) +{ + (nregs != 8 ? regs[nregs++] : stack[sp++]) = value; +} + +void call(bridges::cpp_uno::shared::UnoInterfaceProxy* pProxy, + bridges::cpp_uno::shared::VtableSlot slot, typelib_TypeDescriptionReference* returnType, + const sal_Int32 count, typelib_MethodParameter* parameters, void* returnValue, + void** arguments, uno_Any** exception) +{ + static_assert(sizeof(sal_uInt64) == sizeof(void*)); + typelib_TypeDescription* aReturnTD = nullptr; + TYPELIB_DANGER_GET(&aReturnTD, returnType); + const ReturnKind eRetKind = getReturnKind(aReturnTD); + const bool retConv = bridges::cpp_uno::shared::relatesToInterfaceType(aReturnTD); + void* ret = retConv ? alloca(aReturnTD->nSize) : returnValue; + + sal_uInt64** thisPtr = reinterpret_cast(pProxy->getCppI()) + slot.offset; + + sal_uInt64* gpr = static_cast(alloca((count + 16) * sizeof(sal_uInt64) + 32)); + sal_uInt64* fpr = &gpr[8]; + sal_uInt64* stack = &gpr[16]; + sal_uInt64* frame = &gpr[16 + count]; + void** cppArgs = static_cast(alloca(count * sizeof(void*))); + typelib_TypeDescription** ptds + = static_cast(alloca(count * sizeof(typelib_TypeDescription*))); + + sal_Int32 sp = 0; + sal_Int32 nGPR = 0; + sal_Int32 nFPR = 0; + gpr[nGPR++] = reinterpret_cast(thisPtr); + + for (sal_Int32 i = 0; i != count; ++i) + { + if (!parameters[i].bOut && bridges::cpp_uno::shared::isSimpleType(parameters[i].pTypeRef)) + { + cppArgs[i] = 0; + switch (parameters[i].pTypeRef->eTypeClass) + { + case typelib_TypeClass_BOOLEAN: + pushArgument(*static_cast(arguments[i]), stack, sp, gpr, nGPR); + break; + case typelib_TypeClass_BYTE: + pushArgument(*static_cast(arguments[i]), stack, sp, gpr, nGPR); + break; + case typelib_TypeClass_SHORT: + pushArgument(*static_cast(arguments[i]), stack, sp, gpr, nGPR); + break; + case typelib_TypeClass_UNSIGNED_SHORT: + pushArgument(*static_cast(arguments[i]), stack, sp, gpr, nGPR); + break; + case typelib_TypeClass_LONG: + case typelib_TypeClass_ENUM: + pushArgument(*static_cast(arguments[i]), stack, sp, gpr, nGPR); + break; + case typelib_TypeClass_UNSIGNED_LONG: + pushArgument(*static_cast(arguments[i]), stack, sp, gpr, nGPR); + break; + case typelib_TypeClass_HYPER: + pushArgument(*static_cast(arguments[i]), stack, sp, gpr, nGPR); + break; + case typelib_TypeClass_UNSIGNED_HYPER: + pushArgument(*static_cast(arguments[i]), stack, sp, gpr, nGPR); + break; + case typelib_TypeClass_FLOAT: + pushArgument(*static_cast(arguments[i]), stack, sp, fpr, nFPR); + break; + case typelib_TypeClass_DOUBLE: + pushArgument(*static_cast(arguments[i]), stack, sp, fpr, nFPR); + break; + case typelib_TypeClass_CHAR: + pushArgument(*static_cast(arguments[i]), stack, sp, gpr, nGPR); + break; + default: + assert(false); + } + } + else + { + typelib_TypeDescription* ptd = 0; + 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(reinterpret_cast(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, + pProxy->getBridge()->getUno2Cpp()); + ptds[i] = ptd; + pushArgument(reinterpret_cast(cppArgs[i]), stack, sp, gpr, nGPR); + } + else + { + cppArgs[i] = 0; + pushArgument(reinterpret_cast(arguments[i]), stack, sp, gpr, nGPR); + TYPELIB_DANGER_RELEASE(ptd); + } + } + } + + __try + { + callVirtualFunction(stack, frame, (*thisPtr)[slot.index], ret); + } + __except (msvc_filterCppException(GetExceptionInformation(), *exception, + pProxy->getBridge()->getCpp2Uno())) + { + for (sal_Int32 i = 0; i != count; ++i) + { + if (cppArgs[i] != 0) + { + uno_destructData(cppArgs[i], ptds[i], + reinterpret_cast(css::uno::cpp_release)); + TYPELIB_DANGER_RELEASE(ptds[i]); + } + } + TYPELIB_DANGER_RELEASE(aReturnTD); + return; + } + + *exception = 0; + for (sal_Int32 i = 0; i != count; ++i) + { + if (cppArgs[i] != 0) + { + if (parameters[i].bOut) + { + if (parameters[i].bIn) + { + uno_destructData(arguments[i], ptds[i], 0); + } + uno_copyAndConvertData(arguments[i], cppArgs[i], ptds[i], + pProxy->getBridge()->getCpp2Uno()); + } + uno_destructData(cppArgs[i], ptds[i], + reinterpret_cast(css::uno::cpp_release)); + TYPELIB_DANGER_RELEASE(ptds[i]); + } + } + + switch (eRetKind) + { + case RETURN_KIND_REG: + switch (aReturnTD->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, aReturnTD->nSize); + break; + case typelib_TypeClass_FLOAT: + case typelib_TypeClass_DOUBLE: + std::memcpy(ret, fpr, aReturnTD->nSize); + break; + default: + assert(false); + } + break; + case RETURN_KIND_HFA_FLOAT: + switch (aReturnTD->nSize) + { + case 16: + std::memcpy(static_cast(ret) + 12, fpr + 3, 4); + [[fallthrough]]; + case 12: + std::memcpy(static_cast(ret) + 8, fpr + 2, 4); + [[fallthrough]]; + case 8: + std::memcpy(static_cast(ret) + 4, fpr + 1, 4); + [[fallthrough]]; + case 4: + std::memcpy(ret, fpr, 4); + break; + default: + assert(false); + } + break; + case RETURN_KIND_HFA_DOUBLE: + std::memcpy(ret, fpr, aReturnTD->nSize); + break; + case RETURN_KIND_INDIRECT: + break; + } + + if (retConv) + { + uno_copyAndConvertData(returnValue, ret, aReturnTD, pProxy->getBridge()->getCpp2Uno()); + uno_destructData(ret, aReturnTD, reinterpret_cast(css::uno::cpp_release)); + } + TYPELIB_DANGER_RELEASE(aReturnTD); +} +} + +namespace bridges::cpp_uno::shared +{ +void unoInterfaceProxyDispatch(uno_Interface* pUnoI, typelib_TypeDescription const* pMemberDescr, + void* pReturn, void** pArgs, uno_Any** ppException) +{ + UnoInterfaceProxy* pProxy = static_cast(pUnoI); + switch (pMemberDescr->eTypeClass) + { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + { + typelib_InterfaceAttributeTypeDescription const* atd + = reinterpret_cast(pMemberDescr); + VtableSlot slot(getVtableSlot(atd)); + if (pReturn != 0) + { // getter + call(pProxy, slot, atd->pAttributeTypeRef, 0, 0, pReturn, pArgs, ppException); + } + else + { // setter + typelib_MethodParameter param = { 0, atd->pAttributeTypeRef, true, false }; + typelib_TypeDescriptionReference* pReturnTD = nullptr; + typelib_typedescriptionreference_new(&pReturnTD, typelib_TypeClass_VOID, + OUString("void").pData); + slot.index += 1; + call(pProxy, slot, pReturnTD, 1, ¶m, pReturn, pArgs, ppException); + typelib_typedescriptionreference_release(pReturnTD); + } + break; + } + case typelib_TypeClass_INTERFACE_METHOD: + { + typelib_InterfaceMethodTypeDescription const* mtd + = reinterpret_cast(pMemberDescr); + VtableSlot slot(getVtableSlot(mtd)); + switch (slot.index) + { + case 1: + pUnoI->acquire(pUnoI); + *ppException = 0; + break; + case 2: + pUnoI->release(pUnoI); + *ppException = 0; + break; + case 0: + { + typelib_TypeDescription* td = 0; + TYPELIB_DANGER_GET( + &td, (reinterpret_cast(pArgs[0])->getTypeLibType())); + if (td != 0) + { + uno_Interface* ifc = 0; + pProxy->pBridge->getUnoEnv()->getRegisteredInterface( + pProxy->pBridge->getUnoEnv(), reinterpret_cast(&ifc), + pProxy->oid.pData, + reinterpret_cast(td)); + if (ifc != 0) + { + uno_any_construct(reinterpret_cast(pReturn), &ifc, td, 0); + ifc->release(ifc); + TYPELIB_DANGER_RELEASE(td); + *ppException = 0; + break; + } + TYPELIB_DANGER_RELEASE(td); + } + } + [[fallthrough]]; + default: + call(pProxy, 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/msvc_win32_arm64/vtableslotcall.S b/bridges/source/cpp_uno/msvc_win32_arm64/vtableslotcall.S new file mode 100644 index 000000000..cda427c5c --- /dev/null +++ b/bridges/source/cpp_uno/msvc_win32_arm64/vtableslotcall.S @@ -0,0 +1,72 @@ +/* -*- 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 . + */ + + OPT 2 // disable listing +// macros to add unwind information +#include "ksarm64.h" + OPT 1 // re-enable listing + + EXPORT vtableSlotCall + IMPORT vtableCall + + TEXTAREA, ALIGN=2 + + NESTED_ENTRY vtableSlotCall + + PROLOG_SAVE_REG_PAIR fp, lr, #-192! + PROLOG_SAVE_REG_PAIR x19, x20, #16 + + add x11, sp, 192 + 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] + + bl vtableCall + + ldp x0, x1, [x19] + ldp d0, d1, [x20] + ldp d2, d3, [x20, #16] + + EPILOG_STACK_RESTORE + EPILOG_RESTORE_REG_PAIR x19, x20, #16 + EPILOG_RESTORE_REG_PAIR fp, lr, #192! + EPILOG_RETURN + + NESTED_END vtableSlotCall + + END + +/* vim:set shiftwidth=4 softtabstop=4 expandtab */ -- cgit v1.2.3