[Libreoffice-commits] core.git: bridges/inc bridges/Library_cpp_uno.mk bridges/source Repository.mk solenv/gbuild

Jan-Marek Glogowski (via logerrit) logerrit at kemper.freedesktop.org
Wed Sep 30 01:09:14 UTC 2020


 Repository.mk                                                 |    4 
 bridges/Library_cpp_uno.mk                                    |    7 
 bridges/inc/msvc/arm64.hxx                                    |   59 +
 bridges/inc/msvc/except.hxx                                   |    6 
 bridges/source/cpp_uno/msvc_shared/except.cxx                 |    4 
 bridges/source/cpp_uno/msvc_win32_arm64/abi.cxx               |  158 +++
 bridges/source/cpp_uno/msvc_win32_arm64/abi.hxx               |   34 
 bridges/source/cpp_uno/msvc_win32_arm64/callvirtualfunction.S |   72 +
 bridges/source/cpp_uno/msvc_win32_arm64/cpp2uno.cxx           |  432 ++++++++++
 bridges/source/cpp_uno/msvc_win32_arm64/except.cxx            |  234 +++++
 bridges/source/cpp_uno/msvc_win32_arm64/uno2cpp.cxx           |  341 +++++++
 bridges/source/cpp_uno/msvc_win32_arm64/vtableslotcall.S      |   72 +
 solenv/gbuild/platform/com_MSC_class.mk                       |   16 
 13 files changed, 1433 insertions(+), 6 deletions(-)

New commits:
commit 03aacdb73d2f797768129d54ac971b48756fa51a
Author:     Jan-Marek Glogowski <glogow at fbihome.de>
AuthorDate: Fri Jul 17 22:59:07 2020 +0200
Commit:     Jan-Marek Glogowski <glogow at fbihome.de>
CommitDate: Wed Sep 30 03:08:36 2020 +0200

    bridges: add a Windows Arm64 UNO bridge
    
    Since Microsoft follows the general ARM64 ABI calling conventions,
    and the SEH exception handling is the same, this result is a mixed
    port of the gcc3_linux_aarch64 bridge and the refactored x86-64
    exception handling.
    
    I have no idea, if the complicated 32-bit handling in RaiseInfo()
    is needed, as the ARM64 trampolines definitly use 64-bit code.
    But since this is the first working version, I currently don't
    mind much ;-)
    
    There is definitly more potential for refactoring in the whole
    bridges directory...
    
    Change-Id: I9782a2e99c0231cdd1286af156ad312229eccf39
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/103642
    Tested-by: Jenkins
    Reviewed-by: Jan-Marek Glogowski <glogow at fbihome.de>

diff --git a/Repository.mk b/Repository.mk
index d0aca4e0e982..1c11c61cb189 100644
--- a/Repository.mk
+++ b/Repository.mk
@@ -557,7 +557,9 @@ $(eval $(call gb_Helper_register_libraries_for_install,PLAINLIBS_URE,ure, \
 	) \
 	log_uno_uno \
 	unsafe_uno_uno \
-	$(if $(filter MSC,$(COM)),$(if $(filter INTEL,$(CPUNAME)),msci,mscx),gcc3)_uno \
+	$(if $(filter MSC,$(COM)), \
+        $(if $(filter INTEL,$(CPUNAME)),msci, \
+		$(if $(filter ARM64,$(CPUNAME)),msca,mscx)),gcc3)_uno \
 ))
 
 $(eval $(call gb_Helper_register_libraries_for_install,PRIVATELIBS_URE,ure, \
diff --git a/bridges/Library_cpp_uno.mk b/bridges/Library_cpp_uno.mk
index e1cf6f52cff2..a29f6b56f620 100644
--- a/bridges/Library_cpp_uno.mk
+++ b/bridges/Library_cpp_uno.mk
@@ -21,6 +21,13 @@ $(call gb_LinkTarget_get_target,$(call gb_Library_get_linktarget,gcc3_uno)) : \
 	EXTRAOBJECTLISTS += $(call gb_CustomTarget_get_workdir,bridges/source/cpp_uno/gcc3_linux_arm)/armhelper.objectlist
 endif
 
+else ifeq ($(CPUNAME),ARM64)
+
+bridges_SELECTED_BRIDGE := msvc_win32_arm64
+bridge_exception_objects := cpp2uno uno2cpp abi
+bridge_noopt_objects := except
+bridge_asm_objects := callvirtualfunction vtableslotcall
+
 else ifeq ($(CPUNAME),AARCH64)
 
 ifneq ($(filter ANDROID DRAGONFLY FREEBSD LINUX MACOSX NETBSD OPENBSD,$(OS)),)
diff --git a/bridges/inc/msvc/arm64.hxx b/bridges/inc/msvc/arm64.hxx
new file mode 100644
index 000000000000..fb095446b097
--- /dev/null
+++ b/bridges/inc/msvc/arm64.hxx
@@ -0,0 +1,59 @@
+/* -*- 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 <msvc/except.hxx>
+
+#pragma pack(push, 8)
+
+struct ExceptionType final
+{
+    sal_Int32 _n0; // flags
+    sal_uInt32 _pTypeInfo; // typeinfo
+    sal_Int32 _n1, _n2, _n3; // thiscast
+    sal_Int32 _n4; // object_size
+    sal_uInt32 _pCopyCtor; // copyctor
+    ExceptionTypeInfo exc_type_info;
+
+    explicit ExceptionType(unsigned char* pCode, sal_uInt64 pCodeBase,
+                           typelib_TypeDescription* pTD) throw();
+
+    ExceptionType(const ExceptionType&) = delete;
+    ExceptionType& operator=(const ExceptionType&) = delete;
+};
+
+struct RaiseInfo final
+{
+    sal_Int32 _n0;
+    sal_uInt32 _pDtor;
+    sal_Int32 _n2;
+    sal_uInt32 _types;
+
+    // Additional fields
+    typelib_TypeDescription* _pTD;
+    unsigned char* _code;
+    sal_uInt64 _codeBase;
+
+    explicit RaiseInfo(typelib_TypeDescription* pTD) throw();
+};
+
+#pragma pack(pop)
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/bridges/inc/msvc/except.hxx b/bridges/inc/msvc/except.hxx
index 8ed49a887a24..91a6441006a3 100644
--- a/bridges/inc/msvc/except.hxx
+++ b/bridges/inc/msvc/except.hxx
@@ -38,15 +38,13 @@ constexpr DWORD MSVC_EH_MAGIC_PARAM = 0x19930520;
 // The NT Exception code that msvcrt uses ('msc' | 0xE0000000)
 constexpr DWORD MSVC_EH_MAGIC_CODE = 0xE06D7363;
 
-#ifdef _M_IX86
+#if defined(_M_IX86)
 #define MSVC_EH_PARAMETERS 3 // Number of parameters in exception record for x86
-#else
-#ifdef _M_AMD64
+#elif defined(_M_AMD64) || defined(_M_ARM64)
 #define MSVC_EH_PARAMETERS 4 // Number of parameters in exception record for AMD64
 #else
 #error "Unsupported machine type"
 #endif
-#endif
 
 class type_info;
 struct RaiseInfo;
diff --git a/bridges/source/cpp_uno/msvc_shared/except.cxx b/bridges/source/cpp_uno/msvc_shared/except.cxx
index af6ae6934e60..f6914922a14f 100644
--- a/bridges/source/cpp_uno/msvc_shared/except.cxx
+++ b/bridges/source/cpp_uno/msvc_shared/except.cxx
@@ -41,6 +41,8 @@
 #include <msvc/x86.hxx>
 #elif defined(_M_AMD64)
 #include <msvc/amd64.hxx>
+#elif defined(_M_ARM64)
+#include <msvc/arm64.hxx>
 #else
 #error "Unsupported machine type"
 #endif
@@ -137,7 +139,7 @@ ExceptionInfos::~ExceptionInfos() throw()
 RaiseInfo* ExceptionInfos::getRaiseInfo(typelib_TypeDescription* pTD) throw()
 {
     static ExceptionInfos* s_pInfos = []() {
-#ifdef _M_AMD64
+#if defined _M_AMD64 || defined _M_ARM64
         SYSTEM_INFO systemInfo;
         GetSystemInfo(&systemInfo);
         allocationGranularity = systemInfo.dwAllocationGranularity;
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 000000000000..c88873143898
--- /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 <sal/config.h>
+#include <sal/types.h>
+
+#include <cassert>
+
+#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<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;
+}
+
+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<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/msvc_win32_arm64/abi.hxx b/bridges/source/cpp_uno/msvc_win32_arm64/abi.hxx
new file mode 100644
index 000000000000..38a61161ca62
--- /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 <typelib/typedescription.h>
+
+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 000000000000..e03bff1d2d55
--- /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 000000000000..cfefa60e748a
--- /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 <sal/config.h>
+
+#include <cassert>
+#include <cstdarg>
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+
+#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 <msvc/arm64.hxx>
+
+#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<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;
+    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<void*>(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_ReleaseFunc>(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<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 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<char*>(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<typelib_InterfaceAttributeTypeDescription*>(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, &param, gpr, fpr, stack, indirectRet);
+            }
+        }
+        break;
+        case typelib_TypeClass_INTERFACE_METHOD:
+            switch (functionIndex)
+            {
+                case 1:
+                    proxy->acquireProxy();
+                    break;
+                case 2:
+                    proxy->releaseProxy();
+                    break;
+                case 0:
+                {
+                    typelib_TypeDescription* td = nullptr;
+                    TYPELIB_DANGER_GET(&td,
+                                       (reinterpret_cast<uno::Type*>(gpr[1])->getTypeLibType()));
+                    if (td != 0 && td->eTypeClass == typelib_TypeClass_INTERFACE)
+                    {
+                        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 != 0)
+                        {
+                            uno_any_construct(reinterpret_cast<uno_Any*>(indirectRet), &ifc, td,
+                                              reinterpret_cast<uno_AcquireFunc>(uno::cpp_acquire));
+                            ifc->release();
+                            TYPELIB_DANGER_RELEASE(td);
+                            break;
+                        }
+                        TYPELIB_DANGER_RELEASE(td);
+                    }
+                }
+                    [[fallthrough]];
+                default:
+                    typelib_InterfaceMethodTypeDescription* pMethodTD
+                        = reinterpret_cast<typelib_InterfaceMethodTypeDescription*>(
+                            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, <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<void**>(code)[3] = reinterpret_cast<void*>(&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<Slot*>(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<typelib_InterfaceAttributeTypeDescription*>(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 000000000000..8cc380c5d79b
--- /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 <sal/config.h>
+
+#include <memory>
+
+#include <malloc.h>
+#include <new.h>
+#include <typeinfo>
+#include <signal.h>
+
+#include <rtl/alloc.h>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+
+#include <com/sun/star/uno/Any.hxx>
+#include <msvc/arm64.hxx>
+#include <except.hxx>
+
+#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
+    // &copyConstruct
+    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<void**>(target + code_size) = pTD;
+    *reinterpret_cast<void**>(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<void**>(target + code_size) = pTD;
+    *reinterpret_cast<void**>(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<void*>(&exc_type_info), static_cast<void*>(pRTTI), len);
+    _pTypeInfo = static_cast<sal_uInt32>(reinterpret_cast<sal_uInt64>(&exc_type_info) - pCodeBase);
+    GenerateCopyConstructorTrampoline(pCode, pTD);
+
+    assert(pCodeBase <= reinterpret_cast<sal_uInt64>(pCode)
+           && (reinterpret_cast<sal_uInt64>(pCode) - pCodeBase < 0x100000000));
+    _pCopyCtor = static_cast<sal_uInt32>(reinterpret_cast<sal_uInt64>(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<typelib_CompoundTypeDescription*>(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<int[]>(nLen);
+
+    nLen = 0;
+    for (pCompTD = reinterpret_cast<typelib_CompoundTypeDescription*>(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<unsigned char*>(std::malloc(totalSize));
+    int pCodeOffset = 0;
+
+    // New base of types array, starts after Trampoline D-Tor / C-Tors
+    DWORD* types = reinterpret_cast<DWORD*>(pCode + codeSize);
+
+    // New base of ExceptionType array, starts after types array
+    unsigned char* etMem = pCode + codeSize + typeInfoArraySize;
+    int etMemOffset = 0;
+
+    _codeBase = reinterpret_cast<sal_uInt64>(pCode)
+                & ~static_cast<sal_uInt64>(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<sal_Int32>(reinterpret_cast<sal_uInt64>(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<sal_Int32>(reinterpret_cast<sal_uInt64>(types) - _codeBase);
+    // Fill types: (nLen, _offset to ExceptionType1, ...ExceptionType2, ...)
+    types[0] = nLen;
+
+    int nPos = 1;
+    for (pCompTD = reinterpret_cast<typelib_CompoundTypeDescription*>(pTD); pCompTD;
+         pCompTD = pCompTD->pBaseTypeDescription)
+    {
+        // Create instance in mem block with placement new
+        ExceptionType* et = new (etMem + etMemOffset) ExceptionType(
+            pCode + pCodeOffset, _codeBase, reinterpret_cast<typelib_TypeDescription*>(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<DWORD>(reinterpret_cast<sal_uInt64>(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 000000000000..a0c2adc6f6d8
--- /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 <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 <msvc/arm64.hxx>
+
+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<sal_uInt64**>(pProxy->getCppI()) + slot.offset;
+
+    sal_uInt64* gpr = static_cast<sal_uInt64*>(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<void**>(alloca(count * sizeof(void*)));
+    typelib_TypeDescription** ptds
+        = static_cast<typelib_TypeDescription**>(alloca(count * sizeof(typelib_TypeDescription*)));
+
+    sal_Int32 sp = 0;
+    sal_Int32 nGPR = 0;
+    sal_Int32 nFPR = 0;
+    gpr[nGPR++] = reinterpret_cast<sal_uInt64>(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<sal_Bool*>(arguments[i]), stack, sp, gpr, nGPR);
+                    break;
+                case typelib_TypeClass_BYTE:
+                    pushArgument(*static_cast<sal_Int8*>(arguments[i]), stack, sp, gpr, nGPR);
+                    break;
+                case typelib_TypeClass_SHORT:
+                    pushArgument(*static_cast<sal_Int16*>(arguments[i]), stack, sp, gpr, nGPR);
+                    break;
+                case typelib_TypeClass_UNSIGNED_SHORT:
+                    pushArgument(*static_cast<sal_uInt16*>(arguments[i]), stack, sp, gpr, nGPR);
+                    break;
+                case typelib_TypeClass_LONG:
+                case typelib_TypeClass_ENUM:
+                    pushArgument(*static_cast<sal_Int32*>(arguments[i]), stack, sp, gpr, nGPR);
+                    break;
+                case typelib_TypeClass_UNSIGNED_LONG:
+                    pushArgument(*static_cast<sal_uInt32*>(arguments[i]), stack, sp, gpr, nGPR);
+                    break;
+                case typelib_TypeClass_HYPER:
+                    pushArgument(*static_cast<sal_Int64*>(arguments[i]), stack, sp, gpr, nGPR);
+                    break;
+                case typelib_TypeClass_UNSIGNED_HYPER:
+                    pushArgument(*static_cast<sal_uInt64*>(arguments[i]), stack, sp, gpr, nGPR);
+                    break;
+                case typelib_TypeClass_FLOAT:
+                    pushArgument(*static_cast<sal_uInt32*>(arguments[i]), stack, sp, fpr, nFPR);
+                    break;
+                case typelib_TypeClass_DOUBLE:
+                    pushArgument(*static_cast<sal_uInt64*>(arguments[i]), stack, sp, fpr, nFPR);
+                    break;
+                case typelib_TypeClass_CHAR:
+                    pushArgument(*static_cast<sal_Unicode*>(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<sal_uInt64>(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<sal_uInt64>(cppArgs[i]), stack, sp, gpr, nGPR);
+            }
+            else
+            {
+                cppArgs[i] = 0;
+                pushArgument(reinterpret_cast<sal_uInt64>(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<uno_ReleaseFunc>(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<uno_ReleaseFunc>(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<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 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<uno_ReleaseFunc>(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<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 != 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, &param, pReturn, pArgs, ppException);
+                typelib_typedescriptionreference_release(pReturnTD);
+            }
+            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 = 0;
+                    break;
+                case 2:
+                    pUnoI->release(pUnoI);
+                    *ppException = 0;
+                    break;
+                case 0:
+                {
+                    typelib_TypeDescription* td = 0;
+                    TYPELIB_DANGER_GET(
+                        &td, (reinterpret_cast<css::uno::Type*>(pArgs[0])->getTypeLibType()));
+                    if (td != 0)
+                    {
+                        uno_Interface* ifc = 0;
+                        pProxy->pBridge->getUnoEnv()->getRegisteredInterface(
+                            pProxy->pBridge->getUnoEnv(), reinterpret_cast<void**>(&ifc),
+                            pProxy->oid.pData,
+                            reinterpret_cast<typelib_InterfaceTypeDescription*>(td));
+                        if (ifc != 0)
+                        {
+                            uno_any_construct(reinterpret_cast<uno_Any*>(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 000000000000..cda427c5c207
--- /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 */
diff --git a/solenv/gbuild/platform/com_MSC_class.mk b/solenv/gbuild/platform/com_MSC_class.mk
index 09dd48dc8754..8a71ca3422bb 100644
--- a/solenv/gbuild/platform/com_MSC_class.mk
+++ b/solenv/gbuild/platform/com_MSC_class.mk
@@ -134,6 +134,21 @@ fi
 endef
 
 # AsmObject class
+ifeq ($(CPUNAME),ARM64)
+gb_AsmObject_get_source = $(1)/$(2).S
+
+# Code needs a preprozessor step .S -> .asm -> .o
+define gb_AsmObject__command
+$(call gb_Output_announce,$(2),$(true),ASM,3)
+$(call gb_Helper_abbreviate_dirs,\
+    mkdir -p $(dir $(1)) $(dir $(4)) && \
+    "$(CC)" -nologo -EP -D_M_ARM64 $(SOLARINC) $(3) > $(subst .o,.asm,$(1)) && \
+    "$(ML_EXE)" $(gb_AFLAGS) -g -errorReport:prompt -o $(1) $(subst .o,.asm,$(1)), \
+    ) && \
+    echo "$(1) : $(3)" > $(4)
+endef
+
+else # !ARM64
 gb_AsmObject_get_source = $(1)/$(2).asm
 
 define gb_AsmObject__command
@@ -146,6 +161,7 @@ $(call gb_Helper_abbreviate_dirs,\
 	echo "$(1) : $(3)" > $(4)
 endef
 
+endif
 
 # LinkTarget class
 


More information about the Libreoffice-commits mailing list