summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan-Marek Glogowski <glogow@fbihome.de>2020-07-17 22:59:07 +0200
committerJan-Marek Glogowski <glogow@fbihome.de>2020-09-30 03:08:36 +0200
commit03aacdb73d2f797768129d54ac971b48756fa51a (patch)
tree7902012ef175d3649d404e0eaa0e739b924414ec
parentf11dc8335c9bae837823c14d059388b8d5965dcb (diff)
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@fbihome.de>
-rw-r--r--Repository.mk4
-rw-r--r--bridges/Library_cpp_uno.mk7
-rw-r--r--bridges/inc/msvc/arm64.hxx59
-rw-r--r--bridges/inc/msvc/except.hxx6
-rw-r--r--bridges/source/cpp_uno/msvc_shared/except.cxx4
-rw-r--r--bridges/source/cpp_uno/msvc_win32_arm64/abi.cxx158
-rw-r--r--bridges/source/cpp_uno/msvc_win32_arm64/abi.hxx34
-rw-r--r--bridges/source/cpp_uno/msvc_win32_arm64/callvirtualfunction.S72
-rw-r--r--bridges/source/cpp_uno/msvc_win32_arm64/cpp2uno.cxx432
-rw-r--r--bridges/source/cpp_uno/msvc_win32_arm64/except.cxx234
-rw-r--r--bridges/source/cpp_uno/msvc_win32_arm64/uno2cpp.cxx341
-rw-r--r--bridges/source/cpp_uno/msvc_win32_arm64/vtableslotcall.S72
-rw-r--r--solenv/gbuild/platform/com_MSC_class.mk16
13 files changed, 1433 insertions, 6 deletions
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) = &copyConstruct;
+}
+
+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