Awesome Job! this is a great step. Highly appreciated on my side.



Am 05.06.2026 um 17:12 schrieb Dave Fisher:
I want to highlight the two hugely important contributions in this commit.

1. Native Apple Silicon support.
2. Python 3.10 support.

A big thanks to Jim!

Best,
Dave

On Jun 5, 2026, at 8:46 AM, [email protected] wrote:

This is an automated email from the ASF dual-hosted git repository.

jimjag pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/openoffice.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 5e139d9fe4 Native Apple Silicon (arm64) support and bundled Python 
3.10 baseline
5e139d9fe4 is described below

commit 5e139d9fe42a654147771da4118aea6285c03168
Author: Jim Jagielski <[email protected]>
AuthorDate: Fri Jun 5 09:44:36 2026 -0400

    Native Apple Silicon (arm64) support and bundled Python 3.10 baseline

    Squashed combination of two efforts, applied onto trunk as a single
    commit. (trunk is not intended to be buildable; this lands the work for
    reference/integration.)

    === Apple Silicon (macOS arm64 / AAPCS64) ===
    Build plumbing: set_soenv.in + source_soenv.sh arm64 Darwin branch
    (CPU=R, CPUNAME=AARCH64, OUTPATH=unxmaccr); new solenv/inc/unxmaccr.mk
    and unx.mk dispatch; macro.hxx AARCH64 arch string; osarch.pm +
    gbuild/platform/macosx.mk arch entries; configure.ac arm64 host
    detection, Big Sur+ version math, and 11.0 deployment target.

    C++/UNO bridge (new s5abi_macosx_aarch64): abi.cxx/hxx AAPCS64 classifier
    (HFA + <=16B/>16B size rules), uno2cpp + call.s AArch64 trampoline,
    cpp2uno incoming path + privateSnippetExecutor + AArch64 codeSnippet
    codegen (x8 indirect-result handled, not displacing this/x0), share.hxx
    __cxa_exception reserved-member alignment fix; Library_cpp_uno.mk +
    makefile.mk wiring. sal/osl/unx/interlck.c arm64 atomics (__sync_* ->
    LSE).

    Externals: openssl darwin64-arm64-cc; icu arm64 little-endian. (NSS 3.39
    deferred -- too old for arm64.)

    Packaging/JVM: Info.plist LSMinimumSystemVersion 11.0; installer
    download.pm/worker.pm/update_module_ignore_lists.pl recognize unxmaccr;
    jvmfwk modern macOS JDK discovery (/Library/Java/JavaVirtualMachines +
    Contents/Home probe).

    The ABI/atomics/trampoline/JDK-discovery code was unit-tested natively
    on an arm64 macOS host; a full AOO build (and bridgetest) was not run.
    Code-signing infra (mandatory for arm64 distribution) is NOT included.

    === Bundled Python 2.7.18 -> 3.10 baseline (Unix/macOS first) ===
    pyversion.mk/_dmake.mk -> 3.10.18 (single version knob). Shipped .py
    fixes: imp -> types.ModuleType (pythonscript.py, pythonloader.py) and
    file() -> open(); mailmerge.py Py3 email module imports + encoders.
    Windows Python 3 build and the makefile.mk/d.lst/configure.ac Py3 work
    are NOT included (separate, larger effort).

    NOTE: macOS 11 becomes the minimum supported version. Python 3.10 is
    EOL 2026-10; the version knob allows a later bump.
---
main/bridges/Library_cpp_uno.mk                    |  18 +
.../source/cpp_uno/s5abi_macosx_aarch64/abi.cxx    | 261 +++++++++
.../source/cpp_uno/s5abi_macosx_aarch64/abi.hxx    |  86 +++
.../source/cpp_uno/s5abi_macosx_aarch64/call.s     | 168 ++++++
.../cpp_uno/s5abi_macosx_aarch64/cpp2uno.cxx       | 543 +++++++++++++++++++
.../source/cpp_uno/s5abi_macosx_aarch64/except.cxx | 358 +++++++++++++
.../cpp_uno/s5abi_macosx_aarch64/makefile.mk       |  81 +++
.../source/cpp_uno/s5abi_macosx_aarch64/share.hxx  | 116 ++++
.../cpp_uno/s5abi_macosx_aarch64/uno2cpp.cxx       | 581 +++++++++++++++++++++
main/configure.ac                                  |  42 +-
main/icu/icu4c-4_2_1-src.patch                     |   2 +-
main/jvmfwk/plugins/sunmajor/pluginlib/util.cxx    |  14 +
main/openssl/makefile.mk                           |   4 +
main/python/pyversion.mk                           |   4 +-
main/python/pyversion_dmake.mk                     |   4 +-
main/pyuno/source/loader/pythonloader.py           |   6 +-
main/sal/osl/unx/interlck.c                        |  23 +
main/sal/rtl/source/macro.hxx                      |   2 +
main/scripting/source/pyprov/mailmerge.py          |  16 +-
main/scripting/source/pyprov/pythonscript.py       |  10 +-
main/set_soenv.in                                  |   8 +
main/setup_native/source/mac/Info.plist.langpack   |   2 +-
main/solenv/bin/modules/installer/download.pm      |   4 +
main/solenv/bin/modules/installer/worker.pm        |   4 +
main/solenv/bin/modules/osarch.pm                  |  12 +-
main/solenv/bin/update_module_ignore_lists.pl      |   1 +
main/solenv/gbuild/platform/macosx.mk              |   2 +
main/solenv/inc/unx.mk                             |   4 +
main/solenv/inc/unxmaccr.mk                        |  42 ++
main/source_soenv.sh                               |   3 +
main/sysui/desktop/macosx/Info.plist               |   2 +-
31 files changed, 2391 insertions(+), 32 deletions(-)

diff --git a/main/bridges/Library_cpp_uno.mk b/main/bridges/Library_cpp_uno.mk
index d868df954f..0d8525362a 100644
--- a/main/bridges/Library_cpp_uno.mk
+++ b/main/bridges/Library_cpp_uno.mk
@@ -431,6 +431,24 @@ $(eval $(call 
gb_Library_add_exception_objects,$(COMNAME)_uno,\
        bridges/source/cpp_uno/s5abi_macosx_x86-64/uno2cpp \
))

+###########################################################
+else ifeq ($(OS)-$(CPUNAME)-$(COMNAME),MACOSX-AARCH64-s5abi)
+###########################################################
+# Apple Silicon (arm64) bridge. The COMNAME is "s5abi" macOS-wide (set in
+# solenv/gbuild/platform/macosx.mk); for arm64 the actual calling convention
+# is AAPCS64, so "s5abi" here is a historical label, not a literal ABI claim.
+
+$(eval $(call gb_Library_add_exception_objects,$(COMNAME)_uno,\
+       bridges/source/cpp_uno/s5abi_macosx_aarch64/abi \
+       bridges/source/cpp_uno/s5abi_macosx_aarch64/except \
+       bridges/source/cpp_uno/s5abi_macosx_aarch64/cpp2uno \
+       bridges/source/cpp_uno/s5abi_macosx_aarch64/uno2cpp \
+))
+
+$(eval $(call gb_Library_add_asmobjects,$(COMNAME)_uno,\
+       bridges/source/cpp_uno/s5abi_macosx_aarch64/call \
+))
+
#########################################################
else ifeq ($(OS)-$(CPUNAME)-$(COMNAME),NETBSD-INTEL-gcc3)
#########################################################
diff --git a/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/abi.cxx 
b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/abi.cxx
new file mode 100644
index 0000000000..d51c5ccf12
--- /dev/null
+++ b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/abi.cxx
@@ -0,0 +1,261 @@
+/**************************************************************
+ *
+ * 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
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *************************************************************/
+
+
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_bridges.hxx"
+
+// This is an implementation of the parameter-classification rules of the
+// AArch64 procedure call standard ("Procedure Call Standard for the Arm 64-bit
+// Architecture", ARM IHI 0055), with the deviations documented in Apple's
+// "Writing ARM64 Code for Apple Platforms".
+//
+// Unlike the System V AMD64 ABI (used by the x86-64 bridge), AAPCS64 does not
+// split aggregates into per-eightbyte INTEGER/SSE classes.  Instead:
+//   * scalars go in one GPR (x) or one FP/SIMD (v) register;
+//   * a Homogeneous Floating-point Aggregate (HFA: <= 4 members, all the same
+//     FP type, recursively) goes in consecutive v registers;
+//   * any other aggregate <= 16 bytes goes in 1-2 GPRs;
+//   * a non-HFA aggregate > 16 bytes is passed indirectly (a pointer to a
+//     caller-allocated copy).
+// Register fill is "all or nothing": if an aggregate does not fit entirely in
+// the remaining registers of its bank, it is passed wholly on the stack.
+//
+// This is a clean-room implementation from the public specifications; see
+// ../../../../AAPCS64_BRIDGE_SPEC.md.  libffi's aarch64 backend was consulted
+// only as a behavioural reference; no code is copied.
+
+#include "abi.hxx"
+
+#include <rtl/ustring.hxx>
+
+using namespace aarch64;
+
+namespace {
+
+// The element type of a Homogeneous Floating-point Aggregate.
+enum HfaKind
+{
+    HFA_NONE,       // not (yet) an HFA
+    HFA_FLOAT,      // all members are FLOAT (4-byte)
+    HFA_DOUBLE      // all members are DOUBLE (8-byte)
+};
+
+// Combine the running HFA kind with a newly-seen member kind.  Two members
+// of different FP types, or any non-FP member, break the homogeneity.
+HfaKind mergeHfa( HfaKind running, HfaKind seen )
+{
+    if ( seen == HFA_NONE )
+        return HFA_NONE;
+    if ( running == HFA_NONE )
+        return seen;
+    return ( running == seen ) ? running : HFA_NONE;
+}
+
+// Recursively determine whether pTypeRef is (part of) a homogeneous
+// floating-point aggregate, accumulating the element kind and member count.
+//
+// Returns false the moment homogeneity is violated (a non-FP scalar, or a
+// second distinct FP type, or > 4 elements).  A FLOAT/DOUBLE scalar counts as
+// a 1-element HFA of itself; a struct flattens its members (and base classes).
+bool collectHfa( typelib_TypeDescriptionReference *pTypeRef, HfaKind &rKind, int 
&rCount )
+{
+    switch ( pTypeRef->eTypeClass )
+    {
+        case typelib_TypeClass_FLOAT:
+            rKind = mergeHfa( rKind, HFA_FLOAT );
+            if ( rKind == HFA_NONE ) return false;
+            return ( ++rCount <= 4 );
+
+        case typelib_TypeClass_DOUBLE:
+            rKind = mergeHfa( rKind, HFA_DOUBLE );
+            if ( rKind == HFA_NONE ) return false;
+            return ( ++rCount <= 4 );
+
+        case typelib_TypeClass_STRUCT:
+        case typelib_TypeClass_EXCEPTION:
+        {
+            typelib_TypeDescription * pTypeDescr = 0;
+            TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
+
+            const typelib_CompoundTypeDescription *pComp =
+                reinterpret_cast<const typelib_CompoundTypeDescription*>( 
pTypeDescr );
+
+            bool bOk = true;
+
+            // Flatten base class first (its members precede ours in layout).
+            if ( pComp->pBaseTypeDescription )
+            {
+                bOk = collectHfa(
+                    pComp->pBaseTypeDescription->aBase.pWeakRef, rKind, rCount 
);
+            }
+
+            for ( sal_Int32 i = 0; bOk && i < pComp->nMembers; ++i )
+                bOk = collectHfa( pComp->ppTypeRefs[i], rKind, rCount );
+
+            TYPELIB_DANGER_RELEASE( pTypeDescr );
+            return bOk;
+        }
+
+        default:
+            // Any non-FP, non-aggregate member breaks homogeneity.
+            rKind = HFA_NONE;
+            return false;
+    }
+}
+
+// Classify an aggregate (STRUCT/EXCEPTION).  Sets the GPR/FPR counts and
+// returns true if it is passed in registers, false if it must be passed
+// indirectly (in memory).
+bool classifyAggregate( typelib_TypeDescriptionReference *pTypeRef, int &nUsedGPR, 
int &nUsedFPR )
+{
+    // First, the HFA test.
+    HfaKind kind = HFA_NONE;
+    int count = 0;
+    if ( collectHfa( pTypeRef, kind, count ) && kind != HFA_NONE && count >= 1 && 
count <= 4 )
+    {
+        nUsedGPR = 0;
+        nUsedFPR = count;       // one v register per member
+        return true;
+    }
+
+    // Otherwise classify by size.
+    typelib_TypeDescription * pTypeDescr = 0;
+    TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
+    sal_Int32 nSize = pTypeDescr->nSize;
+    TYPELIB_DANGER_RELEASE( pTypeDescr );
+
+    if ( nSize > 16 )
+    {
+        // Non-HFA aggregate > 16 bytes => passed indirectly.
+        return false;
+    }
+
+    // Non-HFA aggregate <= 16 bytes => 1 or 2 GPRs (8 bytes each).
+    nUsedGPR = ( nSize > 8 ) ? 2 : 1;
+    nUsedFPR = 0;
+    return true;
+}
+
+} // anonymous namespace
+
+bool aarch64::examine_argument( typelib_TypeDescriptionReference *pTypeRef, bool 
/*bInReturn*/, int &nUsedGPR, int &nUsedFPR )
+{
+    nUsedGPR = 0;
+    nUsedFPR = 0;
+
+    switch ( pTypeRef->eTypeClass )
+    {
+        case typelib_TypeClass_VOID:
+            return true;
+
+        case typelib_TypeClass_CHAR:
+        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_ENUM:
+            nUsedGPR = 1;
+            return true;
+
+        case typelib_TypeClass_FLOAT:
+        case typelib_TypeClass_DOUBLE:
+            nUsedFPR = 1;
+            return true;
+
+        // These UNO types are always handled by the bridge as a pointer/
+        // reference (one GPR), never passed by value through this classifier.
+        case typelib_TypeClass_STRING:
+        case typelib_TypeClass_TYPE:
+        case typelib_TypeClass_ANY:
+        case typelib_TypeClass_TYPEDEF:
+        case typelib_TypeClass_SEQUENCE:
+        case typelib_TypeClass_INTERFACE:
+            nUsedGPR = 1;
+            return true;
+
+        case typelib_TypeClass_STRUCT:
+        case typelib_TypeClass_EXCEPTION:
+            return classifyAggregate( pTypeRef, nUsedGPR, nUsedFPR );
+
+        default:
+#if OSL_DEBUG_LEVEL > 1
+            OSL_TRACE( "Unhandled case: pTypeRef->eTypeClass == %d\n", 
pTypeRef->eTypeClass );
+#endif
+            OSL_ASSERT( 0 );
+    }
+    return false;
+}
+
+bool aarch64::return_in_hidden_param( typelib_TypeDescriptionReference 
*pTypeRef )
+{
+    int g, s;
+    // Returned in registers iff examine_argument() says it fits; otherwise the
+    // caller must pass an indirect-result buffer in x8.
+    return !examine_argument( pTypeRef, true, g, s );
+}
+
+void aarch64::fill_struct( typelib_TypeDescriptionReference *pTypeRef, const 
sal_uInt64 *pGPR, const double *pFPR, void *pStruct )
+{
+    int nUsedGPR = 0;
+    int nUsedFPR = 0;
+    if ( !examine_argument( pTypeRef, true, nUsedGPR, nUsedFPR ) )
+    {
+        // Should not happen: indirect returns are written through x8 directly,
+        // not scattered here.
+        OSL_ASSERT( 0 );
+        return;
+    }
+
+    if ( nUsedFPR > 0 )
+    {
+        // HFA: each member occupies one v register; the members are contiguous
+        // in the struct.  Copy element-by-element to honour FLOAT (4-byte) vs
+        // DOUBLE (8-byte) element width.
+        HfaKind kind = HFA_NONE;
+        int count = 0;
+        collectHfa( pTypeRef, kind, count );
+        if ( kind == HFA_FLOAT )
+        {
+            float *pDest = reinterpret_cast<float *>( pStruct );
+            for ( int i = 0; i < nUsedFPR; ++i )
+                pDest[i] = static_cast<float>( pFPR[i] );
+        }
+        else // HFA_DOUBLE
+        {
+            double *pDest = reinterpret_cast<double *>( pStruct );
+            for ( int i = 0; i < nUsedFPR; ++i )
+                pDest[i] = pFPR[i];
+        }
+    }
+    else
+    {
+        // Non-HFA aggregate <= 16 bytes: raw copy of the 1-2 GPRs.
+        sal_uInt64 *pDest = reinterpret_cast<sal_uInt64 *>( pStruct );
+        for ( int i = 0; i < nUsedGPR; ++i )
+            pDest[i] = pGPR[i];
+    }
+}
diff --git a/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/abi.hxx 
b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/abi.hxx
new file mode 100644
index 0000000000..7d55ac076c
--- /dev/null
+++ b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/abi.hxx
@@ -0,0 +1,86 @@
+/**************************************************************
+ *
+ * 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
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *************************************************************/
+
+
+
+#ifndef _BRIDGES_CPP_UNO_AARCH64_ABI_HXX_
+#define _BRIDGES_CPP_UNO_AARCH64_ABI_HXX_
+
+// This is an implementation of the AArch64 procedure call standard, as
+// described in "Procedure Call Standard for the Arm 64-bit Architecture"
+// (ARM IHI 0055), with the deviations documented in Apple's "Writing ARM64
+// Code for Apple Platforms".  It is a clean-room implementation written from
+// those public specifications; see ../../../../AAPCS64_BRIDGE_SPEC.md.
+
+#include <typelib/typedescription.hxx>
+
+namespace aarch64
+{
+
+/* 8 general purpose registers (x0..x7) are used for parameter passing.
+   Note: the indirect-result-location register x8 is *separate* and is NOT
+   part of this count. */
+const sal_uInt32 MAX_GPR_REGS = 8;
+
+/* 8 SIMD/FP registers (v0..v7) are used for parameter passing. */
+const sal_uInt32 MAX_FPR_REGS = 8;
+
+/* The largest number of registers a single aggregate can occupy: an HFA/HVA
+   may use up to 4 FP registers; a non-HFA aggregate passed in GPRs uses at
+   most 2 (16 bytes / 8). */
+const sal_uInt32 MAX_AGGREGATE_REGS = 4;
+
+/* Count the number of registers required to pass the given type.
+
+   Examines the argument and sets the number of GPR (x) and FPR (v) registers
+   it would consume.  For a Homogeneous Floating-point Aggregate the FPR count
+   is the number of members (<= 4); for a non-HFA aggregate <= 16 bytes the GPR
+   count is 1 or 2; scalars use exactly one register of the appropriate bank.
+
+   Returns false iff the parameter must be passed indirectly (in memory): a
+   non-HFA aggregate larger than 16 bytes.  When bInReturn is true the same
+   classification answers "can this be returned in registers?" (false => the
+   caller must allocate a buffer and pass it in x8).
+*/
+bool examine_argument( typelib_TypeDescriptionReference *pTypeRef, bool bInReturn, int 
&nUsedGPR, int &nUsedFPR );
+
+/** Does a function returning this type use the hidden indirect-result pointer
+    (passed by the caller in x8), or can it return in registers?
+
+    A scalar returns in x0 or v0; an HFA returns in v0..v3; a non-HFA aggregate
+    of <= 16 bytes returns in x0,x1.  Anything larger (non-HFA aggregate
+    > 16 bytes) is returned via the caller-allocated buffer addressed by x8 -
+    that is the "hidden param" case, for which this returns true.
+*/
+bool return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef );
+
+/** Scatter a register-resident return value (an HFA returned in v0..v3, or a
+    non-HFA aggregate <= 16 bytes returned in x0,x1) into the caller's struct.
+
+    pGPR points at the saved x0,x1,... ; pFPR at the saved v0,v1,... (each
+    element the low 8 bytes of a v register, i.e. a double slot).  Only valid
+    when return_in_hidden_param() is false.
+*/
+void fill_struct( typelib_TypeDescriptionReference *pTypeRef, const 
sal_uInt64* pGPR, const double* pFPR, void *pStruct );
+
+} // namespace aarch64
+
+#endif // _BRIDGES_CPP_UNO_AARCH64_ABI_HXX_
diff --git a/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/call.s 
b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/call.s
new file mode 100644
index 0000000000..035b38555a
--- /dev/null
+++ b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/call.s
@@ -0,0 +1,168 @@
+/**************************************************************
+ *
+ * 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
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *************************************************************/
+
+// AArch64 (Apple Silicon, AAPCS64) outgoing-call trampoline for the C++-UNO
+// bridge.  Loads the argument registers from caller-prepared arrays, copies
+// any overflow arguments to the outgoing stack, performs the indirect call,
+// and stores the integer and FP/SIMD return registers back.
+//
+// See AAPCS64_BRIDGE_SPEC.md.  Mach-O assembler syntax; symbols are prefixed
+// with an underscore per the Darwin C ABI.
+//
+// extern "C" void callVirtualFunction(
+//     sal_uInt64  pFunction,     // x0: target C++ virtual method
+//     sal_uInt64  pIndirectRet,  // x1: value for x8 (indirect result ptr), 0 
if none
+//     sal_uInt64 *pGPR,          // x2: 8 words  -> x0..x7
+//     double     *pFPR,          // x3: 8 doubles -> d0..d7
+//     sal_uInt64 *pStack,        // x4: overflow-arg words
+//     sal_uInt32  nStackWords,   // x5: number of 8-byte overflow words
+//     sal_uInt64 *pGPRReturn,    // x6: [out] x0,x1
+//     double     *pFPRReturn);   // x7: [out] d0..d3 (HFA up to 4 elements)
+
+    .text
+    .globl _callVirtualFunction
+    .p2align 2
+_callVirtualFunction:
+    // prologue: save fp/lr and the callee-saved registers we use
+    stp     x29, x30, [sp, #-16]!
+    stp     x19, x20, [sp, #-16]!
+    stp     x21, x22, [sp, #-16]!
+    stp     x23, x24, [sp, #-16]!
+    mov     x29, sp
+
+    // stash inputs that must survive the call into callee-saved registers
+    mov     x19, x0                     // pFunction
+    mov     x20, x2                     // pGPR
+    mov     x21, x3                     // pFPR
+    mov     x22, x6                     // pGPRReturn
+    mov     x23, x7                     // pFPRReturn
+    mov     x24, x1                     // x8 indirect-result value
+
+    // allocate and copy the outgoing overflow stack arguments.
+    // bytes = ((nStackWords + 1) & ~1) * 8, to keep sp 16-byte aligned.
+    add     x9, x5, #1
+    bic     x9, x9, #1
+    lsl     x9, x9, #3
+    sub     sp, sp, x9
+    mov     x10, #0
+Lcvf_copy:
+    cmp     x10, x5
+    b.ge    Lcvf_copied
+    ldr     x11, [x4, x10, lsl #3]
+    str     x11, [sp, x10, lsl #3]
+    add     x10, x10, #1
+    b       Lcvf_copy
+Lcvf_copied:
+
+    // load the FP/SIMD argument registers d0..d7
+    ldp     d0, d1, [x21, #0]
+    ldp     d2, d3, [x21, #16]
+    ldp     d4, d5, [x21, #32]
+    ldp     d6, d7, [x21, #48]
+
+    // load the GP argument registers x0..x7 and the x8 indirect-result reg
+    mov     x8, x24
+    ldp     x6, x7, [x20, #48]
+    ldp     x4, x5, [x20, #32]
+    ldp     x2, x3, [x20, #16]
+    ldp     x0, x1, [x20, #0]
+
+    // perform the virtual call
+    blr     x19
+
+    // store the return registers
+    str     x0, [x22, #0]
+    str     x1, [x22, #8]
+    str     d0, [x23, #0]
+    str     d1, [x23, #8]
+    str     d2, [x23, #16]
+    str     d3, [x23, #24]
+
+    // epilogue
+    mov     sp, x29
+    ldp     x23, x24, [sp], #16
+    ldp     x21, x22, [sp], #16
+    ldp     x19, x20, [sp], #16
+    ldp     x29, x30, [sp], #16
+    ret
+
+// ---------------------------------------------------------------------------
+// privateSnippetExecutor: the incoming (cpp2uno) register-spill executor.
+//
+// Reached by a BR from a per-vtable-slot code snippet (see codeSnippet() in
+// cpp2uno.cxx) with:
+//   x16 = (nVtableOffset << 32) | nFunctionIndex  (low bit 0x80000000 flags a
+//         hidden/indirect return)
+//   x0..x7, d0..d7, x8 = the original incoming arguments (untouched)
+//   sp  = the caller's stack-argument area (overflow)
+//   x30 = return address back into the original C++ caller
+//
+// It spills the argument registers to a save area and calls cpp_vtable_call,
+// then loads the return value back into x0/x1 and d0/d1 (or d0 for fp).
+//
+//   typelib_TypeClass cpp_vtable_call(
+//       sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
+//       void** gpreg, void** fpreg, void** ovrflw,
+//       void* pIndirectReturn, sal_uInt64* pRegisterReturn);
+//
+// Frame (176 bytes): [0]=x29,x30  [16..79]=x0..x7  [80..143]=d0..d7
+//                    [144..159]=return buffer.
+    .globl _privateSnippetExecutor
+    .p2align 2
+_privateSnippetExecutor:
+    mov     x17, sp                     // x17 = ovrflw (incoming stack args)
+    stp     x29, x30, [sp, #-176]!
+    mov     x29, sp
+
+    stp     x0, x1, [sp, #16]           // save GP argument registers x0..x7
+    stp     x2, x3, [sp, #32]
+    stp     x4, x5, [sp, #48]
+    stp     x6, x7, [sp, #64]
+
+    stp     d0, d1, [sp, #80]           // save FP/SIMD argument registers 
d0..d7
+    stp     d2, d3, [sp, #96]
+    stp     d4, d5, [sp, #112]
+    stp     d6, d7, [sp, #128]
+
+    mov     w0, w16                     // nFunctionIndex (low 32 bits)
+    lsr     x1, x16, #32                // nVtableOffset (high 32 bits)
+    add     x2, sp, #16                 // gpreg
+    add     x3, sp, #80                 // fpreg
+    mov     x4, x17                     // ovrflw
+    mov     x5, x8                      // pIndirectReturn (x8 indirect-result 
reg)
+    add     x6, sp, #144                // pRegisterReturn (16-byte buffer)
+    bl      _cpp_vtable_call
+
+    cmp     w0, #10                     // typelib_TypeClass_FLOAT
+    b.eq    Lpse_float
+    cmp     w0, #11                     // typelib_TypeClass_DOUBLE
+    b.eq    Lpse_float
+    // integer / pointer / <=16B aggregate: load both banks; caller reads the
+    // ones that matter for its return type.
+    ldp     x0, x1, [sp, #144]
+    ldp     d0, d1, [sp, #144]
+    b       Lpse_done
+Lpse_float:
+    ldr     d0, [sp, #144]
+Lpse_done:
+    mov     sp, x29
+    ldp     x29, x30, [sp], #176
+    ret
diff --git a/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/cpp2uno.cxx 
b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/cpp2uno.cxx
new file mode 100644
index 0000000000..6fa6bac7a2
--- /dev/null
+++ b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/cpp2uno.cxx
@@ -0,0 +1,543 @@
+/**************************************************************
+ *
+ * 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
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *************************************************************/
+
+
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_bridges.hxx"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <hash_map>
+
+#include <rtl/alloc.h>
+#include <osl/mutex.hxx>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include "com/sun/star/uno/RuntimeException.hpp"
+#include <uno/data.h>
+#include <typelib/typedescription.hxx>
+
+#include "bridges/cpp_uno/shared/bridge.hxx"
+#include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx"
+#include "bridges/cpp_uno/shared/types.hxx"
+#include "bridges/cpp_uno/shared/vtablefactory.hxx"
+
+#include "abi.hxx"
+#include "share.hxx"
+
+using namespace ::osl;
+using namespace ::rtl;
+using namespace ::com::sun::star::uno;
+
+//==================================================================================================
+
+// Perform the UNO call
+//
+// We must convert the parameters stored in gpreg, fpreg and ovrflw to UNO
+// arguments and call pThis->getUnoI()->pDispatcher.
+//
+// gpreg:  this, [gpr params x0..x7]   (the indirect-result ptr is x8, 
separate)
+// fpreg:  [fpr params d0..d7]
+// ovrflw: [gpr or fpr params (properly aligned)]
+//
+// On AArch64 a structure bigger than 16 bytes is returned via the buffer
+// addressed by x8 (pIndirectReturn); 'this' is always x0 = gpreg[0].
+// Simple types are returned in x0,x1 (int) or d0,d1 (fp); HFAs in d0..d3;
+// non-HFA structures <= 16 bytes in x0,x1.
+static typelib_TypeClass cpp2uno_call(
+       bridges::cpp_uno::shared::CppInterfaceProxy * pThis,
+       const typelib_TypeDescription * pMemberTypeDescr,
+       typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void 
return
+       sal_Int32 nParams, typelib_MethodParameter * pParams,
+       void ** gpreg, void ** fpreg, void ** ovrflw,
+       void * pIndirectReturn, // AArch64 x8 indirect-result pointer (0 if 
none)
+       sal_uInt64 * pRegisterReturn /* space for register return */ )
+{
+       unsigned int nr_gpr = 0; //number of gpr registers used
+       unsigned int nr_fpr = 0; //number of fpr registers used
+
+       // return
+       typelib_TypeDescription * pReturnTypeDescr = 0;
+       if (pReturnTypeRef)
+               TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+
+       void * pUnoReturn = 0;
+       void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, 
reconversion need
+
+       if ( pReturnTypeDescr )
+       {
+               if ( aarch64::return_in_hidden_param( pReturnTypeRef ) )
+               {
+                       // AArch64: the indirect-result pointer arrives in x8, 
NOT in the
+                       // first general-purpose argument register (unlike 
x86-64 SysV).
+                       // So we take it from pIndirectReturn and do NOT 
consume a gpreg
+                       // slot here; 'this' still occupies gpreg[0] below.
+                       pCppReturn = pIndirectReturn;
+
+                       pUnoReturn = ( 
bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
+                                                  ? alloca( 
pReturnTypeDescr->nSize )
+                                                  : pCppReturn ); // direct way
+               }
+               else
+                       pUnoReturn = pRegisterReturn; // direct way for simple 
types
+       }
+
+       // pop this (x0)
+       gpreg++;
+       nr_gpr++;
+
+       // stack space
+       // parameters
+       void ** pUnoArgs = reinterpret_cast<void **>(alloca( 4 * sizeof(void *) 
* nParams ));
+       void ** pCppArgs = pUnoArgs + nParams;
+       // indizes of values this have to be converted (interface conversion 
cpp<=>uno)
+       sal_Int32 * pTempIndizes = reinterpret_cast<sal_Int32 *>(pUnoArgs + (2 
* nParams));
+       // type descriptions for reconversions
+       typelib_TypeDescription ** ppTempParamTypeDescr = 
reinterpret_cast<typelib_TypeDescription **>(pUnoArgs + (3 * nParams));
+
+       sal_Int32 nTempIndizes = 0;
+
+       for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+       {
+               const typelib_MethodParameter & rParam = pParams[nPos];
+
+               int nUsedGPR = 0;
+               int nUsedFPR = 0;
+               bool bFitsRegisters = aarch64::examine_argument( 
rParam.pTypeRef, false, nUsedGPR, nUsedFPR );
+               if ( !rParam.bOut && bridges::cpp_uno::shared::isSimpleType( 
rParam.pTypeRef ) ) // value
+               {
+                       // A simple UNO type occupies exactly one register, GPR 
or FPR.
+                       OSL_ASSERT( bFitsRegisters && ( ( nUsedFPR == 1 && nUsedGPR == 
0 ) || ( nUsedFPR == 0 && nUsedGPR == 1 ) ) );
+
+                       if ( nUsedFPR == 1 )
+                       {
+                               if ( nr_fpr < aarch64::MAX_FPR_REGS )
+                               {
+                                       pCppArgs[nPos] = pUnoArgs[nPos] = 
fpreg++;
+                                       nr_fpr++;
+                               }
+                               else
+                                       pCppArgs[nPos] = pUnoArgs[nPos] = 
ovrflw++;
+                       }
+                       else if ( nUsedGPR == 1 )
+                       {
+                               if ( nr_gpr < aarch64::MAX_GPR_REGS )
+                               {
+                                       pCppArgs[nPos] = pUnoArgs[nPos] = 
gpreg++;
+                                       nr_gpr++;
+                               }
+                               else
+                                       pCppArgs[nPos] = pUnoArgs[nPos] = 
ovrflw++;
+                       }
+               }
+               else // struct <= 16 bytes || ptr to complex value || ref
+               {
+                       typelib_TypeDescription * pParamTypeDescr = 0;
+                       TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+                       void *pCppStack;
+                       if ( nr_gpr < aarch64::MAX_GPR_REGS )
+                       {
+                               pCppArgs[nPos] = pCppStack = *gpreg++;
+                               nr_gpr++;
+                       }
+                       else
+                               pCppArgs[nPos] = pCppStack = *ovrflw++;
+
+                       if (! rParam.bIn) // is pure out
+                       {
+                               // uno out is unconstructed mem!
+                               pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize 
);
+                               pTempIndizes[nTempIndizes] = nPos;
+                               // will be released at reconversion
+                               ppTempParamTypeDescr[nTempIndizes++] = 
pParamTypeDescr;
+                       }
+                       else if ( 
bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ) ) // is 
in/inout
+                       {
+                               uno_copyAndConvertData( pUnoArgs[nPos] = alloca( 
pParamTypeDescr->nSize ),
+                                                                               
pCppStack, pParamTypeDescr,
+                                                                               
pThis->getBridge()->getCpp2Uno() );
+                               pTempIndizes[nTempIndizes] = nPos; // has to be 
reconverted
+                               // will be released at reconversion
+                               ppTempParamTypeDescr[nTempIndizes++] = 
pParamTypeDescr;
+                       }
+                       else // direct way
+                       {
+                               pUnoArgs[nPos] = pCppStack;
+                               // no longer needed
+                               TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+                       }
+               }
+       }
+
+       // ExceptionHolder
+       uno_Any aUnoExc; // Any will be constructed by callee
+       uno_Any * pUnoExc = &aUnoExc;
+
+       // invoke uno dispatch call
+       (*pThis->getUnoI()->pDispatcher)( pThis->getUnoI(), pMemberTypeDescr, 
pUnoReturn, pUnoArgs, &pUnoExc );
+
+       // in case an exception occurred...
+       if ( pUnoExc )
+       {
+               // destruct temporary in/inout params
+               for ( ; nTempIndizes--; )
+               {
+                       sal_Int32 nIndex = pTempIndizes[nTempIndizes];
+
+                       if (pParams[nIndex].bIn) // is in/inout => was 
constructed
+                               uno_destructData( pUnoArgs[nIndex], 
ppTempParamTypeDescr[nTempIndizes], 0 );
+                       TYPELIB_DANGER_RELEASE( 
ppTempParamTypeDescr[nTempIndizes] );
+               }
+               if (pReturnTypeDescr)
+                       TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+
+               CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc, 
pThis->getBridge()->getUno2Cpp() ); // has to destruct the any
+               // is here for dummy
+               return typelib_TypeClass_VOID;
+       }
+       else // else no exception occurred...
+       {
+               // temporary params
+               for ( ; nTempIndizes--; )
+               {
+                       sal_Int32 nIndex = pTempIndizes[nTempIndizes];
+                       typelib_TypeDescription * pParamTypeDescr = 
ppTempParamTypeDescr[nTempIndizes];
+
+                       if ( pParams[nIndex].bOut ) // inout/out
+                       {
+                               // convert and assign
+                               uno_destructData( pCppArgs[nIndex], 
pParamTypeDescr, cpp_release );
+                               uno_copyAndConvertData( pCppArgs[nIndex], 
pUnoArgs[nIndex], pParamTypeDescr,
+                                                                               
pThis->getBridge()->getUno2Cpp() );
+                       }
+                       // destroy temp uno param
+                       uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 
);
+
+                       TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+               }
+               // return
+               if ( pCppReturn ) // has complex return
+               {
+                       if ( pUnoReturn != pCppReturn ) // needs reconversion
+                       {
+                               uno_copyAndConvertData( pCppReturn, pUnoReturn, 
pReturnTypeDescr,
+                                                                               
pThis->getBridge()->getUno2Cpp() );
+                               // destroy temp uno return
+                               uno_destructData( pUnoReturn, pReturnTypeDescr, 
0 );
+                       }
+                       // complex return ptr is set to return reg
+                       *reinterpret_cast<void **>(pRegisterReturn) = 
pCppReturn;
+               }
+               if ( pReturnTypeDescr )
+               {
+                       typelib_TypeClass eRet = 
(typelib_TypeClass)pReturnTypeDescr->eTypeClass;
+                       TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+                       return eRet;
+               }
+               else
+                       return typelib_TypeClass_VOID;
+       }
+}
+
+
+//==================================================================================================
+extern "C" typelib_TypeClass cpp_vtable_call(
+       sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
+       void ** gpreg, void ** fpreg, void ** ovrflw,
+       void * pIndirectReturn, // AArch64 x8 indirect-result pointer (0 if 
none)
+       sal_uInt64 * pRegisterReturn /* space for register return */ )
+{
+       // gpreg:  this, [other gpr params x0..x7]
+       // fpreg:  [fpr params d0..d7]
+       // ovrflw: [gpr or fpr params (properly aligned)]
+       // pIndirectReturn: x8 (the hidden return buffer), when bit 0x80000000 
set.
+       //
+       // On AArch64 'this' is ALWAYS x0 = gpreg[0]; the hidden return pointer 
is
+       // the separate x8 register, not a displaced first GPR (unlike x86-64 
SysV
+       // where it occupied gpreg[0] and 'this' moved to gpreg[1]).
+       if ( nFunctionIndex & 0x80000000 )
+               nFunctionIndex &= 0x7fffffff;
+
+       void * pThis = gpreg[0];
+       pThis = static_cast<char *>( pThis ) - nVtableOffset;
+
+       bridges::cpp_uno::shared::CppInterfaceProxy * pCppI =
+               
bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( pThis );
+
+       typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
+
+       OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex, 
"### illegal vtable index!\n" );
+       if ( nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex )
+       {
+               throw RuntimeException( OUString::createFromAscii("illegal vtable 
index!"),
+                                                               
reinterpret_cast<XInterface *>( pCppI ) );
+       }
+
+       // determine called method
+       sal_Int32 nMemberPos = 
pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
+       OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member 
index!\n" );
+
+       TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
+
+       typelib_TypeClass eRet;
+       switch ( aMemberDescr.get()->eTypeClass )
+       {
+               case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+               {
+                       typelib_TypeDescriptionReference *pAttrTypeRef =
+                               
reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( aMemberDescr.get() 
)->pAttributeTypeRef;
+
+                       if ( 
pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex )
+                       {
+                               // is GET method
+                               eRet = cpp2uno_call( pCppI, aMemberDescr.get(), 
pAttrTypeRef,
+                                               0, 0, // no params
+                                               gpreg, fpreg, ovrflw, 
pIndirectReturn, pRegisterReturn );
+                       }
+                       else
+                       {
+                               // is SET method
+                               typelib_MethodParameter aParam;
+                               aParam.pTypeRef = pAttrTypeRef;
+                               aParam.bIn              = sal_True;
+                               aParam.bOut             = sal_False;
+
+                               eRet = cpp2uno_call( pCppI, aMemberDescr.get(),
+                                               0, // indicates void return
+                                               1, &aParam,
+                                               gpreg, fpreg, ovrflw, 
pIndirectReturn, pRegisterReturn );
+                       }
+                       break;
+               }
+               case typelib_TypeClass_INTERFACE_METHOD:
+               {
+                       // is METHOD
+                       switch ( nFunctionIndex )
+                       {
+                               case 1: // acquire()
+                                       pCppI->acquireProxy(); // non virtual 
call!
+                                       eRet = typelib_TypeClass_VOID;
+                                       break;
+                               case 2: // release()
+                                       pCppI->releaseProxy(); // non virtual 
call!
+                                       eRet = typelib_TypeClass_VOID;
+                                       break;
+                               case 0: // queryInterface() opt
+                               {
+                                       // queryInterface([in] type) returns an 
Any (> 16 bytes),
+                                       // so on AArch64 the result buffer is 
x8 (pIndirectReturn),
+                                       // 'this' is gpreg[0], and the type 
argument is the first
+                                       // real parameter, gpreg[1].
+                                       typelib_TypeDescription * pTD = 0;
+                                       TYPELIB_DANGER_GET( &pTD, 
reinterpret_cast<Type *>( gpreg[1] )->getTypeLibType() );
+                                       if ( pTD )
+                                       {
+                                               XInterface * pInterface = 0;
+                                               
(*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)
+                                                       ( 
pCppI->getBridge()->getCppEnv(),
+                                                         reinterpret_cast<void 
**>(&pInterface),
+                                                         pCppI->getOid().pData,
+                                                         
reinterpret_cast<typelib_InterfaceTypeDescription *>( pTD ) );
+
+                                               if ( pInterface )
+                                               {
+                                                       ::uno_any_construct( 
reinterpret_cast<uno_Any *>( pIndirectReturn ),
+                                                                                   
             &pInterface, pTD, cpp_acquire );
+
+                                                       pInterface->release();
+                                                       TYPELIB_DANGER_RELEASE( 
pTD );
+
+                                                       reinterpret_cast<void 
**>( pRegisterReturn )[0] = pIndirectReturn;
+                                                       eRet = 
typelib_TypeClass_ANY;
+                                                       break;
+                                               }
+                                               TYPELIB_DANGER_RELEASE( pTD );
+                                       }
+                               } // else perform queryInterface()
+                               default:
+                               {
+                                       typelib_InterfaceMethodTypeDescription 
*pMethodTD =
+                                               
reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( aMemberDescr.get() 
);
+
+                                       eRet = cpp2uno_call( pCppI, 
aMemberDescr.get(),
+                                                                                
pMethodTD->pReturnTypeRef,
+                                                                                
pMethodTD->nParams,
+                                                                                
pMethodTD->pParams,
+                                                                               
 gpreg, fpreg, ovrflw, pIndirectReturn, pRegisterReturn );
+                               }
+                       }
+                       break;
+               }
+               default:
+               {
+                       throw RuntimeException( OUString::createFromAscii("no member 
description found!"),
+                                                                       
reinterpret_cast<XInterface *>( pCppI ) );
+                       // is here for dummy
+                       eRet = typelib_TypeClass_VOID;
+               }
+       }
+
+       return eRet;
+}
+
+//==================================================================================================
+// The incoming register-spill executor, implemented in call.s.  It is reached
+// via BR from a per-slot snippet (codeSnippet below) with x16 carrying the
+// packed (nVtableOffset << 32) | nFunctionIndex; it spills the argument
+// registers and calls cpp_vtable_call.
+extern "C" void privateSnippetExecutor( void );
+
+// Each snippet is 5 AArch64 instructions (20 bytes) + 4 bytes padding to an
+// 8-byte boundary + two 8-byte literals (the packed index and the executor
+// address) = 40 bytes.
+const int codeSnippetSize = 40;
+
+// Generate a per-vtable-slot trampoline that loads the packed function index
+// into x16 and branches to privateSnippetExecutor(), preserving every
+// argument register.  Uses PC-relative literal loads because AArch64 cannot
+// embed a 64-bit immediate in a single instruction.
+//
+// Layout (offsets in bytes from code):
+//    0:  ldr  x16, #24      ; x16 = nOffsetAndIndex (literal at +24)
+//    4:  ldr  x17, #28      ; x17 = privateSnippetExecutor (literal at +32)
+//    8:  br   x17
+//   12:  (unused / padding)
+//   16:  (padding to 8-byte align the literals at 24)
+//   24:  .quad nOffsetAndIndex
+//   32:  .quad privateSnippetExecutor
+//
+// Note: the snippet creates no stack frame, so the C++ unwinder walks straight
+// through it to the original caller (required for UNO exception propagation).
+unsigned char * codeSnippet( unsigned char * code,
+        sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
+        bool bHasHiddenParam ) SAL_THROW( () )
+{
+       sal_uInt64 nOffsetAndIndex = ( static_cast<sal_uInt64>( nVtableOffset ) << 32 
) | static_cast<sal_uInt64>( nFunctionIndex );
+
+       if ( bHasHiddenParam )
+               nOffsetAndIndex |= 0x80000000;
+
+       sal_uInt32 * p = reinterpret_cast<sal_uInt32 *>( code );
+
+       // ldr x16, #24  -> literal at code+24. imm19 = 24/4 = 6.
+       //   encoding: 0x58000000 | (imm19 << 5) | Rt(16)
+       p[0] = 0x58000000 | ( 6 << 5 ) | 16;
+       // ldr x17, #28  -> literal at code+32 (relative to this insn at +4): 
28.
+       //   imm19 = 28/4 = 7.
+       p[1] = 0x58000000 | ( 7 << 5 ) | 17;
+       // br x17  -> 0xD61F0000 | (Rn(17) << 5)
+       p[2] = 0xD61F0000 | ( 17 << 5 );
+       // p[3] (offset 12) and p[4] (offset 16..20) are padding.
+       p[3] = 0xD503201F; // NOP
+       p[4] = 0xD503201F; // NOP
+
+       // literals, 8-byte aligned at offset 24 and 32
+       *reinterpret_cast<sal_uInt64 *>( code + 24 ) = nOffsetAndIndex;
+       *reinterpret_cast<sal_uInt64 *>( code + 32 ) = 
reinterpret_cast<sal_uInt64>( privateSnippetExecutor );
+
+       return code + codeSnippetSize;
+}
+
+//==================================================================================================
+struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; };
+
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
+{
+    return static_cast< Slot * >(block) + 2;
+}
+
+//==================================================================================================
+sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize(
+    sal_Int32 slotCount)
+{
+    return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
+}
+
+//==================================================================================================
+bridges::cpp_uno::shared::VtableFactory::Slot *
+bridges::cpp_uno::shared::VtableFactory::initializeBlock(
+    void * block, sal_Int32 slotCount)
+{
+    Slot * slots = mapBlockToVtable(block);
+    slots[-2].fn = 0;
+    slots[-1].fn = 0;
+    return slots + slotCount;
+}
+
+//==================================================================================================
+
+unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
+       Slot ** slots, unsigned char * code, /*sal_PtrDiff writetoexecdiff,*/
+       typelib_InterfaceTypeDescription const * type, sal_Int32 
nFunctionOffset,
+       sal_Int32 functionCount, sal_Int32 nVtableOffset )
+{
+       const sal_PtrDiff writetoexecdiff = 0;
+       (*slots) -= functionCount;
+       Slot * s = *slots;
+       for ( sal_Int32 nPos = 0; nPos < type->nMembers; ++nPos )
+       {
+               typelib_TypeDescription * pTD = 0;
+
+               TYPELIB_DANGER_GET( &pTD, type->ppMembers[ nPos ] );
+               OSL_ASSERT( pTD );
+
+               if ( typelib_TypeClass_INTERFACE_ATTRIBUTE == pTD->eTypeClass )
+               {
+                       typelib_InterfaceAttributeTypeDescription *pAttrTD =
+                               
reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( pTD );
+
+                       // get method
+                       (s++)->fn = code + writetoexecdiff;
+                       code = codeSnippet( code, nFunctionOffset++, 
nVtableOffset,
+                                                               
aarch64::return_in_hidden_param( pAttrTD->pAttributeTypeRef ) );
+
+                       if ( ! pAttrTD->bReadOnly )
+                       {
+                               // set method
+                               (s++)->fn = code + writetoexecdiff;
+                               code = codeSnippet( code, nFunctionOffset++, 
nVtableOffset, false );
+                       }
+               }
+               else if ( typelib_TypeClass_INTERFACE_METHOD == pTD->eTypeClass 
)
+               {
+                       typelib_InterfaceMethodTypeDescription *pMethodTD =
+                               
reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( pTD );
+
+                       (s++)->fn = code + writetoexecdiff;
+                       code = codeSnippet( code, nFunctionOffset++, 
nVtableOffset,
+                                                               
aarch64::return_in_hidden_param( pMethodTD->pReturnTypeRef ) );
+               }
+               else
+                       OSL_ASSERT( false );
+
+               TYPELIB_DANGER_RELEASE( pTD );
+       }
+       return code;
+}
+
+//==================================================================================================
+void bridges::cpp_uno::shared::VtableFactory::flushCode(
+       unsigned char const *, unsigned char const * )
+{
+}
diff --git a/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/except.cxx 
b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/except.cxx
new file mode 100644
index 0000000000..60784a4172
--- /dev/null
+++ b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/except.cxx
@@ -0,0 +1,358 @@
+/**************************************************************
+ *
+ * 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
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *************************************************************/
+
+
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_bridges.hxx"
+
+#if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6))
+#include <exception>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <cxxabi.h>
+#include <hash_map>
+#include <sys/param.h>
+
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <osl/diagnose.h>
+#include <osl/mutex.hxx>
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include "com/sun/star/uno/RuntimeException.hpp"
+#include <typelib/typedescription.hxx>
+#include <uno/any2.h>
+
+#include "share.hxx"
+
+
+using namespace ::std;
+using namespace ::osl;
+using namespace ::rtl;
+using namespace ::com::sun::star::uno;
+using namespace ::__cxxabiv1;
+
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+
+void dummy_can_throw_anything( char const * )
+{
+}
+
+//==================================================================================================
+static OUString toUNOname( char const * p ) SAL_THROW( () )
+{
+#if OSL_DEBUG_LEVEL > 1
+    char const * start = p;
+#endif
+
+    // example: N3com3sun4star4lang24IllegalArgumentExceptionE
+
+       OUStringBuffer buf( 64 );
+    OSL_ASSERT( 'N' == *p );
+    ++p; // skip N
+
+    while ('E' != *p)
+    {
+        // read chars count
+        long n = (*p++ - '0');
+        while ('0' <= *p && '9' >= *p)
+        {
+            n *= 10;
+            n += (*p++ - '0');
+        }
+        buf.appendAscii( p, n );
+        p += n;
+        if ('E' != *p)
+            buf.append( (sal_Unicode)'.' );
+    }
+
+#if OSL_DEBUG_LEVEL > 1
+    OUString ret( buf.makeStringAndClear() );
+    OString c_ret( OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ) );
+    fprintf( stderr, "> toUNOname(): %s => %s\n", start, c_ret.getStr() );
+    return ret;
+#else
+    return buf.makeStringAndClear();
+#endif
+}
+
+//==================================================================================================
+class RTTI
+{
+    typedef hash_map< OUString, type_info *, OUStringHash > t_rtti_map;
+
+    Mutex m_mutex;
+       t_rtti_map m_rttis;
+    t_rtti_map m_generatedRttis;
+
+    void * m_hApp;
+
+public:
+    RTTI() SAL_THROW( () );
+    ~RTTI() SAL_THROW( () );
+
+    type_info * getRTTI( typelib_CompoundTypeDescription * ) SAL_THROW( () );
+};
+
+//__________________________________________________________________________________________________
+RTTI::RTTI() SAL_THROW( () )
+    : m_hApp( dlopen( 0, RTLD_LAZY ) )
+{
+}
+
+//__________________________________________________________________________________________________
+RTTI::~RTTI() SAL_THROW( () )
+{
+    dlclose( m_hApp );
+}
+
+//__________________________________________________________________________________________________
+type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr ) 
SAL_THROW( () )
+{
+    type_info * rtti;
+
+    OUString const & unoName = *(OUString const *)&pTypeDescr->aBase.pTypeName;
+
+    MutexGuard guard( m_mutex );
+    t_rtti_map::const_iterator iFind( m_rttis.find( unoName ) );
+    if (iFind == m_rttis.end())
+    {
+        // RTTI symbol
+        OStringBuffer buf( 64 );
+        buf.append( RTL_CONSTASCII_STRINGPARAM("_ZTIN") );
+        sal_Int32 index = 0;
+        do
+        {
+            OUString token( unoName.getToken( 0, '.', index ) );
+            buf.append( token.getLength() );
+            OString c_token( OUStringToOString( token, 
RTL_TEXTENCODING_ASCII_US ) );
+            buf.append( c_token );
+        }
+        while (index >= 0);
+        buf.append( 'E' );
+
+        OString symName( buf.makeStringAndClear() );
+        rtti = static_cast<std::type_info *>(dlsym( m_hApp, symName.getStr() 
));
+
+        if (rtti)
+        {
+            pair< t_rtti_map::iterator, bool > insertion(
+                m_rttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
+            OSL_ENSURE( insertion.second, "### inserting new rtti failed?!" );
+        }
+        else
+        {
+            // try to lookup the symbol in the generated rtti map
+            t_rtti_map::const_iterator iFind2( m_generatedRttis.find( unoName 
) );
+            if (iFind2 == m_generatedRttis.end())
+            {
+                // we must generate it !
+                // symbol and rtti-name is nearly identical,
+                // the symbol is prefixed with _ZTI
+                char const * rttiName = symName.getStr() +4;
+#if OSL_DEBUG_LEVEL > 1
+                fprintf( stderr,"generated rtti for %s\n", rttiName );
+                const OString aCUnoName = OUStringToOString( unoName, 
RTL_TEXTENCODING_UTF8);
+                OSL_TRACE( "TypeInfo for \"%s\" not found and cannot be 
generated.\n", aCUnoName.getStr());
+#endif
+#ifndef AOO_BYPASS_RTTI
+                if (pTypeDescr->pBaseTypeDescription)
+                {
+                    // ensure availability of base
+                    type_info * base_rtti = getRTTI(
+                        (typelib_CompoundTypeDescription 
*)pTypeDescr->pBaseTypeDescription );
+                    rtti = new __si_class_type_info(
+                        strdup( rttiName ), (__class_type_info *)base_rtti );
+                }
+                else
+                {
+                    // this class has no base class
+                    rtti = new __class_type_info( strdup( rttiName ) );
+                }
+#else
+                rtti = NULL;
+#endif
+                bool bOK = m_generatedRttis.insert( t_rtti_map::value_type( 
unoName, rtti )).second;
+                OSL_ENSURE( bOK, "### inserting new generated rtti failed?!" );
+            }
+            else // taking already generated rtti
+            {
+                rtti = iFind2->second;
+            }
+        }
+    }
+    else
+    {
+        rtti = iFind->second;
+    }
+
+    return rtti;
+}
+
+//--------------------------------------------------------------------------------------------------
+static void deleteException( void * pExc )
+{
+    __cxa_exception const * header = static_cast<__cxa_exception const 
*>(pExc) - 1;
+    /* More __cxa_exception mumbo-jumbo. See share.hxx and fillUnoException() 
below */
+    if (header->exceptionDestructor != &deleteException)
+    {
+        header = reinterpret_cast<__cxa_exception const *>(reinterpret_cast<char 
const *>(header) - 8);
+    }
+    if( !header->exceptionType)
+    {
+        return; // NOTE: leak for now
+    }
+    typelib_TypeDescription * pTD = 0;
+    OUString unoName( toUNOname( header->exceptionType->name() ) );
+    ::typelib_typedescription_getByName( &pTD, unoName.pData );
+    OSL_ENSURE( pTD, "### unknown exception type! leaving out destruction => 
leaking!!!" );
+    if (pTD)
+    {
+               ::uno_destructData( pExc, pTD, cpp_release );
+               ::typelib_typedescription_release( pTD );
+       }
+}
+
+//==================================================================================================
+void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp )
+{
+#if OSL_DEBUG_LEVEL > 1
+    OString cstr(
+        OUStringToOString(
+            *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName 
),
+            RTL_TEXTENCODING_ASCII_US ) );
+    fprintf( stderr, "> uno exception occurred: %s\n", cstr.getStr() );
+#endif
+    void * pCppExc;
+    type_info * rtti;
+
+    {
+    // construct cpp exception object
+       typelib_TypeDescription * pTypeDescr = 0;
+       TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType );
+    OSL_ASSERT( pTypeDescr );
+    if (! pTypeDescr)
+    {
+        throw RuntimeException(
+            OUString( RTL_CONSTASCII_USTRINGPARAM("cannot get typedescription for 
type ") ) +
+            *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName 
),
+            Reference< XInterface >() );
+    }
+
+       pCppExc = __cxa_allocate_exception( pTypeDescr->nSize );
+       ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp 
);
+
+       // destruct uno exception
+       ::uno_any_destruct( pUnoExc, 0 );
+    // avoiding locked counts
+    static RTTI * s_rtti = 0;
+    if (! s_rtti)
+    {
+        MutexGuard guard( Mutex::getGlobalMutex() );
+        if (! s_rtti)
+        {
+#ifdef LEAK_STATIC_DATA
+            s_rtti = new RTTI();
+#else
+            static RTTI rtti_data;
+            s_rtti = &rtti_data;
+#endif
+        }
+    }
+       rtti = (type_info *)s_rtti->getRTTI( (typelib_CompoundTypeDescription 
*) pTypeDescr );
+    TYPELIB_DANGER_RELEASE( pTypeDescr );
+    OSL_ENSURE( rtti, "### no rtti for throwing exception!" );
+    if (! rtti)
+    {
+        throw RuntimeException(
+            OUString( RTL_CONSTASCII_USTRINGPARAM("no rtti for type ") ) +
+            *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName 
),
+            Reference< XInterface >() );
+    }
+    }
+
+       __cxa_throw( pCppExc, rtti, deleteException );
+}
+
+//==================================================================================================
+void fillUnoException( __cxa_exception * header, uno_Any * pUnoExc, 
uno_Mapping * pCpp2Uno )
+{
+    if (! header)
+    {
+        RuntimeException aRE(
+            OUString( RTL_CONSTASCII_USTRINGPARAM("no exception header!") ),
+            Reference< XInterface >() );
+        Type const & rType = ::getCppuType( &aRE );
+        uno_type_any_constructAndConvert( pUnoExc, &aRE, 
rType.getTypeLibType(), pCpp2Uno );
+#if OSL_DEBUG_LEVEL > 0
+        OString cstr( OUStringToOString( aRE.Message, 
RTL_TEXTENCODING_ASCII_US ) );
+        OSL_ENSURE( 0, cstr.getStr() );
+#endif
+        return;
+    }
+
+    /*
+     * Handle the case where we are built on llvm 10 (or later) but are running
+     * on an earlier version (eg, community builds). In this situation the
+     * reserved ptr doesn't exist in the struct returned and so the offsets
+     * that header uses are wrong. This assumes that reserved isn't used
+     * and that referenceCount is always >0 in the cases we handle.
+     * See share.hxx for the definition of __cxa_exception
+     */
+    if (*reinterpret_cast<void **>(header) == 0)
+    {
+        header = reinterpret_cast<__cxa_exception *>(reinterpret_cast<char 
*>(header) + 8);
+    }
+
+       typelib_TypeDescription * pExcTypeDescr = 0;
+    OUString unoName( toUNOname( header->exceptionType->name() ) );
+#if OSL_DEBUG_LEVEL > 1
+    OString cstr_unoName( OUStringToOString( unoName, 
RTL_TEXTENCODING_ASCII_US ) );
+    fprintf( stderr, "> c++ exception occurred: %s\n", cstr_unoName.getStr() );
+#endif
+       typelib_typedescription_getByName( &pExcTypeDescr, unoName.pData );
+    if (0 == pExcTypeDescr)
+    {
+        RuntimeException aRE(
+            OUString( RTL_CONSTASCII_USTRINGPARAM("exception type not found: 
") ) + unoName,
+            Reference< XInterface >() );
+        Type const & rType = ::getCppuType( &aRE );
+        uno_type_any_constructAndConvert( pUnoExc, &aRE, 
rType.getTypeLibType(), pCpp2Uno );
+#if OSL_DEBUG_LEVEL > 0
+        OString cstr( OUStringToOString( aRE.Message, 
RTL_TEXTENCODING_ASCII_US ) );
+        OSL_ENSURE( 0, cstr.getStr() );
+#endif
+    }
+    else
+    {
+        // construct uno exception any
+        uno_any_constructAndConvert( pUnoExc, header->adjustedPtr, 
pExcTypeDescr, pCpp2Uno );
+        typelib_typedescription_release( pExcTypeDescr );
+    }
+}
+
+}
diff --git a/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/makefile.mk 
b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/makefile.mk
new file mode 100644
index 0000000000..af6c6c22d4
--- /dev/null
+++ b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/makefile.mk
@@ -0,0 +1,81 @@
+#**************************************************************
+#
+#  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
+#
+#  Unless required by applicable law or agreed to in writing,
+#  software distributed under the License is distributed on an
+#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+#  specific language governing permissions and limitations
+#  under the License.
+#
+#**************************************************************
+
+
+
+PRJ=..$/..$/..
+
+PRJNAME=bridges
+TARGET=$(COMNAME)_uno
+LIBTARGET=no
+ENABLE_EXCEPTIONS=TRUE
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE :  settings.mk
+
+# --- Files --------------------------------------------------------
+
+# Apple Silicon (arm64 / AAPCS64) C++-UNO bridge. CPU=R, CPUNAME=AARCH64.
+# Note: the "s5abi" in this directory's name is the macOS-wide COMNAME (see
+# solenv/gbuild/platform/macosx.mk); the actual arm64 calling convention is
+# AAPCS64, so "s5abi" here is a historical label, not a literal ABI claim.
+.IF "$(OS)$(CPU)" == "MACOSXR"
+
+.IF "$(cppu_no_leak)" == ""
+CFLAGS += -DLEAK_STATIC_DATA
+.ENDIF
+
+# In case someone enabled the non-standard -fomit-frame-pointer which does not
+# work with the .cxx sources in this directory:
+CFLAGSCXX += -fno-omit-frame-pointer -fnon-call-exceptions
+
+SLOFILES= \
+       $(SLO)$/abi.obj                 \
+       $(SLO)$/except.obj              \
+       $(SLO)$/cpp2uno.obj             \
+       $(SLO)$/uno2cpp.obj             \
+       $(SLO)$/call.obj
+
+SHL1TARGET= $(TARGET)
+
+SHL1DEF=$(MISC)$/$(SHL1TARGET).def
+SHL1IMPLIB=i$(TARGET)
+SHL1VERSIONMAP=..$/..$/bridge_exports.map
+SHL1RPATH=URELIB
+
+SHL1OBJS = $(SLOFILES)
+SHL1LIBS = $(SLB)$/cpp_uno_shared.lib
+
+SHL1STDLIBS= \
+       $(CPPULIB)                      \
+       $(SALLIB)
+
+.ENDIF
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE :  target.mk
+
+# Assemble the AArch64 call trampoline (call.s) into call.obj, mirroring the
+# pattern rule used by the gcc3_linux_arm bridge for its armhelper.S.
+$(SLO)$/%.obj: %.s
+       $(CXX) -c -o $(SLO)$/$(@:b).o $< -fPIC ; touch $@
diff --git a/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/share.hxx 
b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/share.hxx
new file mode 100644
index 0000000000..e4fcf4dbf9
--- /dev/null
+++ b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/share.hxx
@@ -0,0 +1,116 @@
+/**************************************************************
+ *
+ * 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
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *************************************************************/
+
+
+
+#include "uno/mapping.h"
+
+#include <typeinfo>
+#include <exception>
+#include <cstddef>
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+
+void dummy_can_throw_anything( char const * );
+
+typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__)));
+
+// ----- the following structure is compatible with the one declared in 
libunwind's unwind.h
+// (use forced types)
+
+struct _Unwind_Exception
+{
+    uint64_t exception_class;
+    void * exception_cleanup;
+    uintptr_t private_1;
+    uintptr_t private_2;
+};
+
+struct __cxa_exception
+{
+    /* From LLVM 10 a reserved member was added at the top of the struct on
+       64-bit targets. Who the hell does that?
+       https://reviews.llvm.org/rG674ec1eb16678b8addc02a4b0534ab383d22fa77
+       It is required on arm64 (Apple Silicon): the trailing _Unwind_Exception
+       must be 16-byte aligned within the allocation, and only WITH this member
+       does unwindHeader land at a 16-byte boundary (offset 96, vs a misaligned
+       88 without it).  Verified empirically against this host's libc++abi.
+       NOTE: Apple clang version != upstream LLVM version. */
+    void *reserved;
+    size_t referenceCount;
+    ::std::type_info *exceptionType;
+    void (*exceptionDestructor)(void *);
+    ::std::unexpected_handler unexpectedHandler;
+    ::std::terminate_handler terminateHandler;
+    __cxa_exception *nextException;
+    int handlerCount;
+    int handlerSwitchValue;
+    const unsigned char *actionRecord;
+    const unsigned char *languageSpecificData;
+    void *catchTemp;
+    void *adjustedPtr;
+    _Unwind_Exception unwindHeader;
+};
+
+extern "C" void *__cxa_allocate_exception(
+    std::size_t thrown_size ) throw();
+extern "C" void __cxa_throw (
+    void *thrown_exception, std::type_info *tinfo, void (*dest) (void *) ) 
__attribute__((noreturn));
+
+struct __cxa_eh_globals
+{
+    __cxa_exception *caughtExceptions;
+    unsigned int uncaughtExceptions;
+};
+extern "C" __cxa_eh_globals *__cxa_get_globals () throw();
+
+// -----
+
+// on OSX 64bit the class_type_info classes are specified
+// in http://refspecs.linuxbase.org/cxxabi-1.86.html#rtti but
+// these details are not generally available in a public header
+// of most development environments. So we define them here.
+// NOTE: 
https://www.hexblog.com/wp-content/uploads/2012/06/Recon-2012-Skochinsky-Compiler-Internals.pdf
+class __class_type_info : public std::type_info
+{
+public:
+        explicit __class_type_info( const char* pRttiName)
+        : std::type_info( pRttiName)
+        {}
+};
+
+class __si_class_type_info : public __class_type_info
+{
+        const __class_type_info* mpBaseType;
+public:
+        explicit __si_class_type_info( const char* pRttiName, 
__class_type_info* pBaseType)
+        : __class_type_info( pRttiName), mpBaseType( pBaseType)
+        {}
+};
+
+//==================================================================================================
+void raiseException(
+    uno_Any * pUnoExc, uno_Mapping * pUno2Cpp );
+//==================================================================================================
+void fillUnoException(
+    __cxa_exception * header, uno_Any *, uno_Mapping * pCpp2Uno );
+}
diff --git a/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/uno2cpp.cxx 
b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/uno2cpp.cxx
new file mode 100644
index 0000000000..adaa3f2a5f
--- /dev/null
+++ b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/uno2cpp.cxx
@@ -0,0 +1,581 @@
+/**************************************************************
+ *
+ * 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
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *************************************************************/
+
+
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_bridges.hxx"
+
+#include <exception>
+#include <typeinfo>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "rtl/alloc.h"
+#include "rtl/ustrbuf.hxx"
+
+#include <com/sun/star/uno/genfunc.hxx>
+#include "com/sun/star/uno/RuntimeException.hpp"
+#include <uno/data.h>
+
+#include <bridges/cpp_uno/shared/bridge.hxx>
+#include <bridges/cpp_uno/shared/types.hxx>
+#include "bridges/cpp_uno/shared/unointerfaceproxy.hxx"
+#include "bridges/cpp_uno/shared/vtables.hxx"
+
+#include "abi.hxx"
+#include "share.hxx"
+
+using namespace ::rtl;
+using namespace ::com::sun::star::uno;
+
+//==================================================================================================
+
+// The AArch64 outgoing-call trampoline, implemented in call.s.  It loads the
+// argument registers from the caller-prepared arrays, copies overflow args to
+// the outgoing stack, performs the indirect call, and returns x0/x1 and 
d0..d3.
+extern "C" void callVirtualFunction(
+    sal_uInt64 pFunction, sal_uInt64 pIndirectRet,
+    sal_uInt64 *pGPR, double *pFPR,
+    sal_uInt64 *pStack, sal_uInt32 nStackWords,
+    sal_uInt64 *pGPRReturn, double *pFPRReturn );
+
+static void callVirtualMethod(void * pThis, sal_uInt32 nVtableIndex,
+                              void * pRegisterReturn, 
typelib_TypeDescriptionReference * pReturnTypeRef, bool bSimpleReturn,
+                              void * pIndirectReturn,
+                              sal_uInt64 *pStack, sal_uInt32 nStack,
+                              sal_uInt64 *pGPR, sal_uInt32 nGPR,
+                              double *pFPR, sal_uInt32 nFPR) 
__attribute__((noinline));
+
+static void callVirtualMethod(void * pThis, sal_uInt32 nVtableIndex,
+                              void * pRegisterReturn, 
typelib_TypeDescriptionReference * pReturnTypeRef, bool bSimpleReturn,
+                              void * pIndirectReturn,
+                              sal_uInt64 *pStack, sal_uInt32 nStack,
+                              sal_uInt64 *pGPR, sal_uInt32 nGPR,
+                              double *pFPR, sal_uInt32 nFPR)
+{
+#if OSL_DEBUG_LEVEL > 1
+    // Let's figure out what is really going on here
+    {
+        fprintf( stderr, "= callVirtualMethod() =\nGPR's (%d): ", nGPR );
+        for ( unsigned int i = 0; i < nGPR; ++i )
+            fprintf( stderr, "0x%lx, ", pGPR[i] );
+        fprintf( stderr, "\nFPR's (%d): ", nFPR );
+        for ( unsigned int i = 0; i < nFPR; ++i )
+            fprintf( stderr, "%f, ", pFPR[i] );
+        fprintf( stderr, "\nStack (%d): ", nStack );
+        for ( unsigned int i = 0; i < nStack; ++i )
+            fprintf( stderr, "0x%lx, ", pStack[i] );
+        fprintf( stderr, "\n" );
+    }
+#endif
+
+    // The call instruction within callVirtualFunction may throw exceptions.  
So
+    // that the compiler handles this correctly, it is important that (a)
+    // callVirtualMethod might call dummy_can_throw_anything (although this 
never
+    // happens at runtime), which in turn can throw exceptions, and (b)
+    // callVirtualMethod is not inlined at its call site (so that any 
exceptions
+    // thrown across the call are caught):
+    if ( !pThis )
+        CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything( "xxx" ); // address 
something
+
+    // Should not happen, but...
+    if ( nFPR > aarch64::MAX_FPR_REGS )
+        nFPR = aarch64::MAX_FPR_REGS;
+    if ( nGPR > aarch64::MAX_GPR_REGS )
+        nGPR = aarch64::MAX_GPR_REGS;
+
+    // Get pointer to the C++ virtual method from the vtable.
+    sal_uInt64 pMethod = *((sal_uInt64 *)pThis);
+    pMethod += 8 * nVtableIndex;
+    pMethod = *((sal_uInt64 *)pMethod);
+
+    // Return register save areas: x0,x1 and d0..d3 (HFA up to 4 elements).
+    sal_uInt64 gpReturn[2] = { 0, 0 };
+    double fpReturn[4] = { 0, 0, 0, 0 };
+
+    // Ensure the GPR/FPR arrays are the full register width even if fewer were
+    // filled (the trampoline always loads all 8 of each).
+    sal_uInt64 gpr[aarch64::MAX_GPR_REGS];
+    double fpr[aarch64::MAX_FPR_REGS];
+    for ( sal_uInt32 i = 0; i < aarch64::MAX_GPR_REGS; ++i )
+        gpr[i] = ( i < nGPR ) ? pGPR[i] : 0;
+    for ( sal_uInt32 i = 0; i < aarch64::MAX_FPR_REGS; ++i )
+        fpr[i] = ( i < nFPR ) ? pFPR[i] : 0;
+
+    callVirtualFunction(
+        pMethod,
+        reinterpret_cast<sal_uInt64>( pIndirectReturn ), // x8, 0 if none
+        gpr, fpr,
+        pStack, nStack,
+        gpReturn, fpReturn );
+
+    switch (pReturnTypeRef->eTypeClass)
+    {
+    case typelib_TypeClass_HYPER:
+    case typelib_TypeClass_UNSIGNED_HYPER:
+        *reinterpret_cast<sal_uInt64 *>( pRegisterReturn ) = gpReturn[0];
+        break;
+    case typelib_TypeClass_LONG:
+    case typelib_TypeClass_UNSIGNED_LONG:
+    case typelib_TypeClass_ENUM:
+        *reinterpret_cast<sal_uInt32 *>( pRegisterReturn ) = 
*reinterpret_cast<sal_uInt32*>( &gpReturn[0] );
+        break;
+    case typelib_TypeClass_CHAR:
+    case typelib_TypeClass_SHORT:
+    case typelib_TypeClass_UNSIGNED_SHORT:
+        *reinterpret_cast<sal_uInt16 *>( pRegisterReturn ) = 
*reinterpret_cast<sal_uInt16*>( &gpReturn[0] );
+        break;
+    case typelib_TypeClass_BOOLEAN:
+    case typelib_TypeClass_BYTE:
+        *reinterpret_cast<sal_uInt8 *>( pRegisterReturn ) = 
*reinterpret_cast<sal_uInt8*>( &gpReturn[0] );
+        break;
+    case typelib_TypeClass_FLOAT:
+    case typelib_TypeClass_DOUBLE:
+        *reinterpret_cast<double *>( pRegisterReturn ) = fpReturn[0];
+        break;
+    default:
+        {
+            sal_Int32 const nRetSize = pReturnTypeRef->pType->nSize;
+            if (bSimpleReturn && nRetSize <= 16 && nRetSize > 0)
+            {
+                // Register-returned aggregate: an HFA arrives in d0..d3, a
+                // non-HFA <= 16 bytes in x0,x1.  fill_struct picks the right 
one.
+                aarch64::fill_struct( pReturnTypeRef, &gpReturn[0], 
&fpReturn[0], pRegisterReturn);
+            }
+            break;
+        }
+    }
+}
+
+//==================================================================================================
+
+// Macros for easier insertion of values to registers or stack
+// pSV - pointer to the source
+// nr - order of the value [will be increased if stored to register]
+// pFPR, pGPR - pointer to the registers
+// pDS - pointer to the stack [will be increased if stored here]
+
+// The pFPR slot holds the value to be loaded into a v register; the trampoline
+// loads it with LDR d<n>, so float and double are stored the same way here.
+#define INSERT_FLOAT_DOUBLE( pSV, nr, pFPR, pDS ) \
+       if ( nr < aarch64::MAX_FPR_REGS ) \
+               pFPR[nr++] = *reinterpret_cast<double *>( pSV ); \
+       else \
+               *pDS++ = *reinterpret_cast<sal_uInt64 *>( pSV ); // verbatim!
+
+#define INSERT_INT64( pSV, nr, pGPR, pDS ) \
+       if ( nr < aarch64::MAX_GPR_REGS ) \
+               pGPR[nr++] = *reinterpret_cast<sal_uInt64 *>( pSV ); \
+       else \
+               *pDS++ = *reinterpret_cast<sal_uInt64 *>( pSV );
+
+#define INSERT_INT32( pSV, nr, pGPR, pDS ) \
+       if ( nr < aarch64::MAX_GPR_REGS ) \
+               pGPR[nr++] = *reinterpret_cast<sal_uInt32 *>( pSV ); \
+       else \
+               *pDS++ = *reinterpret_cast<sal_uInt32 *>( pSV );
+
+#define INSERT_INT16( pSV, nr, pGPR, pDS ) \
+       if ( nr < aarch64::MAX_GPR_REGS ) \
+               pGPR[nr++] = *reinterpret_cast<sal_uInt16 *>( pSV ); \
+       else \
+               *pDS++ = *reinterpret_cast<sal_uInt16 *>( pSV );
+
+#define INSERT_INT8( pSV, nr, pGPR, pDS ) \
+       if ( nr < aarch64::MAX_GPR_REGS ) \
+               pGPR[nr++] = *reinterpret_cast<sal_uInt8 *>( pSV ); \
+       else \
+               *pDS++ = *reinterpret_cast<sal_uInt8 *>( pSV );
+
+//==================================================================================================
+
+namespace {
+
+void appendCString(OUStringBuffer & buffer, char const * text) {
+    if (text != 0) {
+        buffer.append(
+            OStringToOUString(OString(text), RTL_TEXTENCODING_ISO_8859_1));
+            // use 8859-1 to avoid conversion failure
+    }
+}
+
+}
+
+static void cpp_call(
+       bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
+       bridges::cpp_uno::shared::VtableSlot aVtableSlot,
+       typelib_TypeDescriptionReference * pReturnTypeRef,
+       sal_Int32 nParams, typelib_MethodParameter * pParams,
+       void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
+{
+       // Maxium space for [complex ret ptr], values | ptr ...
+       // (but will be used less - some of the values will be in pGPR and pFPR)
+       sal_uInt64 *pStack = (sal_uInt64 *)__builtin_alloca( (nParams + 3) * 
sizeof(sal_uInt64) );
+       sal_uInt64 *pStackStart = pStack;
+
+       sal_uInt64 pGPR[aarch64::MAX_GPR_REGS];
+       sal_uInt32 nGPR = 0;
+
+       double pFPR[aarch64::MAX_FPR_REGS];
+       sal_uInt32 nFPR = 0;
+
+       // Return
+       typelib_TypeDescription * pReturnTypeDescr = 0;
+       TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
+       OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" );
+
+       void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion 
(see below)
+
+       // Indirect-result pointer. On AArch64 this is passed in the dedicated 
x8
+       // register, NOT as the first general-purpose argument (unlike x86-64 
SysV).
+       // So we do NOT insert it into pGPR here; it is threaded to the 
trampoline
+       // separately as pIndirectReturn.
+       void * pIndirectReturn = 0;
+
+       bool bSimpleReturn = true;
+       if ( pReturnTypeDescr )
+       {
+               if ( aarch64::return_in_hidden_param( pReturnTypeRef ) )
+                       bSimpleReturn = false;
+
+               if ( bSimpleReturn )
+                       pCppReturn = pUnoReturn; // direct way for simple types
+               else
+               {
+                       // complex return via the x8 indirect-result buffer
+                       pCppReturn = 
bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )?
+                                                __builtin_alloca( 
pReturnTypeDescr->nSize ) : pUnoReturn;
+                       pIndirectReturn = pCppReturn;
+               }
+       }
+
+       // Push "this" pointer
+       void * pAdjustedThisPtr = reinterpret_cast< void ** >( pThis->getCppI() 
) + aVtableSlot.offset;
+       INSERT_INT64( &pAdjustedThisPtr, nGPR, pGPR, pStack );
+
+       // Args
+       void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams );
+       // Indizes of values this have to be converted (interface conversion 
cpp<=>uno)
+       sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams);
+       // Type descriptions for reconversions
+       typelib_TypeDescription ** ppTempParamTypeDescr = 
(typelib_TypeDescription **)(pCppArgs + (2 * nParams));
+
+       sal_Int32 nTempIndizes = 0;
+
+       for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+       {
+               const typelib_MethodParameter & rParam = pParams[nPos];
+               typelib_TypeDescription * pParamTypeDescr = 0;
+               TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+               if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( 
pParamTypeDescr ))
+               {
+                       uno_copyAndConvertData( pCppArgs[nPos] = alloca( 8 ), 
pUnoArgs[nPos], pParamTypeDescr,
+                                                                       
pThis->getBridge()->getUno2Cpp() );
+
+                       switch (pParamTypeDescr->eTypeClass)
+                       {
+                       case typelib_TypeClass_HYPER:
+                       case typelib_TypeClass_UNSIGNED_HYPER:
+                               INSERT_INT64( pCppArgs[nPos], nGPR, pGPR, 
pStack );
+                               break;
+                       case typelib_TypeClass_LONG:
+                       case typelib_TypeClass_UNSIGNED_LONG:
+                       case typelib_TypeClass_ENUM:
+                               INSERT_INT32( pCppArgs[nPos], nGPR, pGPR, 
pStack );
+                               break;
+                       case typelib_TypeClass_SHORT:
+                       case typelib_TypeClass_CHAR:
+                       case typelib_TypeClass_UNSIGNED_SHORT:
+                               INSERT_INT16( pCppArgs[nPos], nGPR, pGPR, 
pStack );
+                               break;
+                       case typelib_TypeClass_BOOLEAN:
+                       case typelib_TypeClass_BYTE:
+                               INSERT_INT8( pCppArgs[nPos], nGPR, pGPR, pStack 
);
+                               break;
+                       case typelib_TypeClass_FLOAT:
+                       case typelib_TypeClass_DOUBLE:
+                               INSERT_FLOAT_DOUBLE( pCppArgs[nPos], nFPR, 
pFPR, pStack );
+                               break;
+                       default:
+                               break;
+                       }
+
+                       // no longer needed
+                       TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+               }
+               else // ptr to complex value | ref
+               {
+                       if (! rParam.bIn) // is pure out
+                       {
+                               // cpp out is constructed mem, uno out is not!
+                               uno_constructData(
+                                       pCppArgs[nPos] = alloca( 
pParamTypeDescr->nSize ),
+                                       pParamTypeDescr );
+                               pTempIndizes[nTempIndizes] = nPos; // default 
constructed for cpp call
+                               // will be released at reconversion
+                               ppTempParamTypeDescr[nTempIndizes++] = 
pParamTypeDescr;
+                       }
+                       // is in/inout
+                       else if 
(bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
+                       {
+                               uno_copyAndConvertData(
+                                       pCppArgs[nPos] = alloca( 
pParamTypeDescr->nSize ),
+                                       pUnoArgs[nPos], pParamTypeDescr, 
pThis->getBridge()->getUno2Cpp() );
+
+                               pTempIndizes[nTempIndizes] = nPos; // has to be 
reconverted
+                               // will be released at reconversion
+                               ppTempParamTypeDescr[nTempIndizes++] = 
pParamTypeDescr;
+                       }
+                       else // direct way
+                       {
+                               pCppArgs[nPos] = pUnoArgs[nPos];
+                               // no longer needed
+                               TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+                       }
+                       INSERT_INT64( &(pCppArgs[nPos]), nGPR, pGPR, pStack );
+               }
+       }
+
+       try
+       {
+        try {
+            callVirtualMethod(
+                pAdjustedThisPtr, aVtableSlot.index,
+                pCppReturn, pReturnTypeRef, bSimpleReturn,
+                pIndirectReturn,
+                pStackStart, ( pStack - pStackStart ),
+                pGPR, nGPR,
+                pFPR, nFPR );
+        } catch (Exception &) {
+            throw;
+        } catch (std::exception & e) {
+            OUStringBuffer buf;
+            buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("C++ code threw "));
+            appendCString(buf, typeid(e).name());
+            buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(": "));
+            appendCString(buf, e.what());
+            throw RuntimeException(
+                buf.makeStringAndClear(), Reference< XInterface >());
+        } catch (...) {
+            throw RuntimeException(
+                OUString(
+                    RTL_CONSTASCII_USTRINGPARAM(
+                        "C++ code threw unknown exception")),
+                Reference< XInterface >());
+        }
+
+               // NO exception occurred...
+               *ppUnoExc = 0;
+
+               // reconvert temporary params
+               for ( ; nTempIndizes--; )
+               {
+                       sal_Int32 nIndex = pTempIndizes[nTempIndizes];
+                       typelib_TypeDescription * pParamTypeDescr = 
ppTempParamTypeDescr[nTempIndizes];
+
+                       if (pParams[nIndex].bIn)
+                       {
+                               if (pParams[nIndex].bOut) // inout
+                               {
+                                       uno_destructData( pUnoArgs[nIndex], 
pParamTypeDescr, 0 ); // destroy uno value
+                                       uno_copyAndConvertData( 
pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
+                                                                                     
  pThis->getBridge()->getCpp2Uno() );
+                               }
+                       }
+                       else // pure out
+                       {
+                               uno_copyAndConvertData( pUnoArgs[nIndex], 
pCppArgs[nIndex], pParamTypeDescr,
+                                                                               
pThis->getBridge()->getCpp2Uno() );
+                       }
+                       // destroy temp cpp param => cpp: every param was 
constructed
+                       uno_destructData( pCppArgs[nIndex], pParamTypeDescr, 
cpp_release );
+
+                       TYPELIB_DANGER_RELEASE( pParamTypeDescr );
+               }
+               // return value
+               if (pCppReturn && pUnoReturn != pCppReturn)
+               {
+                       uno_copyAndConvertData( pUnoReturn, pCppReturn, 
pReturnTypeDescr,
+                                                                       
pThis->getBridge()->getCpp2Uno() );
+                       uno_destructData( pCppReturn, pReturnTypeDescr, 
cpp_release );
+               }
+       }
+       catch (...)
+       {
+               // fill uno exception
+               fillUnoException( 
CPPU_CURRENT_NAMESPACE::__cxa_get_globals()->caughtExceptions, *ppUnoExc, 
pThis->getBridge()->getCpp2Uno() );
+
+               // temporary params
+               for ( ; nTempIndizes--; )
+               {
+                       sal_Int32 nIndex = pTempIndizes[nTempIndizes];
+                       // destroy temp cpp param => cpp: every param was 
constructed
+                       uno_destructData( pCppArgs[nIndex], 
ppTempParamTypeDescr[nTempIndizes], cpp_release );
+                       TYPELIB_DANGER_RELEASE( 
ppTempParamTypeDescr[nTempIndizes] );
+               }
+               // return type
+               if (pReturnTypeDescr)
+                       TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
+       }
+}
+
+//==================================================================================================
+
+namespace bridges { namespace cpp_uno { namespace shared {
+
+void unoInterfaceProxyDispatch(
+       uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
+       void * pReturn, void * pArgs[], uno_Any ** ppException )
+{
+       // is my surrogate
+       bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
+               = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * 
>(pUnoI);
+#if OSL_DEBUG_LEVEL > 0
+       typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
+#endif
+
+       switch (pMemberDescr->eTypeClass)
+       {
+       case typelib_TypeClass_INTERFACE_ATTRIBUTE:
+       {
+#if OSL_DEBUG_LEVEL > 0
+               // determine vtable call index
+               sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription 
*)pMemberDescr)->nPosition;
+               OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### member pos 
out of range!" );
+#endif
+               VtableSlot aVtableSlot(
+                               getVtableSlot(
+                                       reinterpret_cast<
+                                       typelib_InterfaceAttributeTypeDescription 
const * >(
+                                               pMemberDescr)));
+
+               if (pReturn)
+               {
+                       // dependent dispatch
+                       cpp_call(
+                               pThis, aVtableSlot,
+                               ((typelib_InterfaceAttributeTypeDescription 
*)pMemberDescr)->pAttributeTypeRef,
+                               0, 0, // no params
+                               pReturn, pArgs, ppException );
+               }
+               else
+               {
+                       // is SET
+                       typelib_MethodParameter aParam;
+                       aParam.pTypeRef =
+                               ((typelib_InterfaceAttributeTypeDescription 
*)pMemberDescr)->pAttributeTypeRef;
+                       aParam.bIn              = sal_True;
+                       aParam.bOut             = sal_False;
+
+                       typelib_TypeDescriptionReference * pReturnTypeRef = 0;
+                       OUString aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") 
);
+                       typelib_typedescriptionreference_new(
+                               &pReturnTypeRef, typelib_TypeClass_VOID, 
aVoidName.pData );
+
+                       // dependent dispatch
+                       aVtableSlot.index += 1; // get, then set method
+                       cpp_call(
+                               pThis, aVtableSlot, // get, then set method
+                               pReturnTypeRef,
+                               1, &aParam,
+                               pReturn, pArgs, ppException );
+
+                       typelib_typedescriptionreference_release( 
pReturnTypeRef );
+               }
+
+               break;
+       }
+       case typelib_TypeClass_INTERFACE_METHOD:
+       {
+#if OSL_DEBUG_LEVEL > 0
+               // determine vtable call index
+               sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription 
*)pMemberDescr)->nPosition;
+               OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### member pos 
out of range!" );
+#endif
+               VtableSlot aVtableSlot(
+                               getVtableSlot(
+                                       reinterpret_cast<
+                                       typelib_InterfaceMethodTypeDescription 
const * >(
+                                               pMemberDescr)));
+
+               switch (aVtableSlot.index)
+               {
+                       // standard calls
+               case 1: // acquire uno interface
+                       (*pUnoI->acquire)( pUnoI );
+                       *ppException = 0;
+                       break;
+               case 2: // release uno interface
+                       (*pUnoI->release)( pUnoI );
+                       *ppException = 0;
+                       break;
+               case 0: // queryInterface() opt
+               {
+                       typelib_TypeDescription * pTD = 0;
+                       TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( 
pArgs[0] )->getTypeLibType() );
+                       if (pTD)
+                       {
+                uno_Interface * pInterface = 0;
+                (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)(
+                    pThis->getBridge()->getUnoEnv(),
+                    (void **)&pInterface, pThis->oid.pData, 
(typelib_InterfaceTypeDescription *)pTD );
+
+                if (pInterface)
+                {
+                    ::uno_any_construct(
+                        reinterpret_cast< uno_Any * >( pReturn ),
+                        &pInterface, pTD, 0 );
+                    (*pInterface->release)( pInterface );
+                    TYPELIB_DANGER_RELEASE( pTD );
+                    *ppException = 0;
+                    break;
+                }
+                TYPELIB_DANGER_RELEASE( pTD );
+            }
+               } // else perform queryInterface()
+               default:
+                       // dependent dispatch
+                       cpp_call(
+                               pThis, aVtableSlot,
+                               ((typelib_InterfaceMethodTypeDescription 
*)pMemberDescr)->pReturnTypeRef,
+                               ((typelib_InterfaceMethodTypeDescription 
*)pMemberDescr)->nParams,
+                               ((typelib_InterfaceMethodTypeDescription 
*)pMemberDescr)->pParams,
+                               pReturn, pArgs, ppException );
+               }
+               break;
+       }
+       default:
+       {
+               ::com::sun::star::uno::RuntimeException aExc(
+                       OUString( RTL_CONSTASCII_USTRINGPARAM("illegal member type 
description!") ),
+                       ::com::sun::star::uno::Reference< 
::com::sun::star::uno::XInterface >() );
+
+               Type const & rExcType = ::getCppuType( &aExc );
+               // binary identical null reference
+               ::uno_type_any_construct( *ppException, &aExc, 
rExcType.getTypeLibType(), 0 );
+       }
+       }
+}
+
+} } }
diff --git a/main/configure.ac b/main/configure.ac
index 3f67e5b3fb..8731dc71f4 100644
--- a/main/configure.ac
+++ b/main/configure.ac
@@ -922,8 +922,8 @@ AC_ARG_WITH(arm-target,
AC_ARG_WITH(macosx-target,
[  --macosx-target            The minimal macOS/OSX deployment and build target

-                              Usage: --with-macosx-target=10.9
-],with_macosx_target=$withval,with_macosx_target=10.9)
+                              Usage: --with-macosx-target=11.0
+],with_macosx_target=$withval,with_macosx_target=11.0)
AC_ARG_WITH(macosx-sdk,
[  --macosx-sdk            The macOS SDK to build against

@@ -1159,9 +1159,29 @@ case "$build_os" in
                fi
                # Don't use OSVERSION until we know no conflicts result from it
                _darwin_version="`uname -r | $AWK -F . '{ print $1 }'`"
-               # FIXME: Assumes 10.x, breaks w/ Big Sur
-               _osx_version="10.`expr $_darwin_version - 4`"
+               # Map the Darwin (XNU) major version to the macOS version.
+               # Darwin 6..19  => macOS 10.(darwin-4)   (10.2 .. 10.15)
+               # Darwin 20+    => macOS (darwin-9)       (11, 12, 13, ...)
+               if test "$_darwin_version" -ge 20; then
+                  _osx_version="`expr $_darwin_version - 9`"
+               else
+                  _osx_version="10.`expr $_darwin_version - 4`"
+               fi
                AC_MSG_NOTICE([Detected Darwin version: $_darwin_version 
($_osx_version)])
+               # Detect the build CPU architecture. Apple Silicon (arm64) 
reports
+               # "arm64" from uname -m and maps to the aarch64 
toolchain/bridge.
+               _darwin_cpu="`uname -m`"
+               case "$_darwin_cpu" in
+                  arm64|aarch64)
+                     AC_MSG_NOTICE([Detected Apple Silicon (arm64) build host])
+                     ;;
+                  x86_64|i*86)
+                     AC_MSG_NOTICE([Detected Intel (x86_64) build host])
+                     ;;
+                  *)
+                     AC_MSG_ERROR([Unsupported macOS CPU architecture: 
$_darwin_cpu])
+                     ;;
+               esac
                ;;
        os2*)
                test_x=no
@@ -3907,10 +3927,20 @@ if test  "$_os" = "Darwin"; then
    sdk_target=$with_macosx_target
    AC_MSG_CHECKING([checking SDK compatibility with OSX $sdk_target])

+   sdk_major=`echo $sdk_target | cut -d"." -f1`
    sdk_minor=`echo $sdk_target | cut -d"." -f2`
+   test -z "$sdk_minor" && sdk_minor=0
+
+   dnl Minimum supported macOS is 11.0 (Big Sur). Pre-11 targets are only
+   dnl accepted down to the old 10.9 floor for legacy Intel builds.
+   if test "$_darwin_cpu" = "arm64" -o "$_darwin_cpu" = "aarch64"; then
+      if test "$sdk_major" -lt "11"; then
+         AC_MSG_ERROR([Apple Silicon (arm64) requires 
--with-macosx-target=11.0 or later])
+      fi
+   fi

-   if test "$sdk_minor" -lt "9"; then
-      AC_MSG_ERROR([SDK version < 10.9 is not longer supported])
+   if test "$sdk_major" -lt "10" -o \( "$sdk_major" -eq "10" -a "$sdk_minor" -lt 
"9" \); then
+      AC_MSG_ERROR([macOS deployment target < 10.9 is no longer supported])
    else
       MACOSX_DEPLOYMENT_TARGET=$sdk_target
       sdk_path=$with_macosx_sdk
diff --git a/main/icu/icu4c-4_2_1-src.patch b/main/icu/icu4c-4_2_1-src.patch
index 77fc719528..572572a3ea 100644
--- a/main/icu/icu4c-4_2_1-src.patch
+++ b/main/icu/icu4c-4_2_1-src.patch
@@ -212,7 +212,7 @@ diff -ru misc/icu/source/tools/genuca/genuca.cpp 
misc/build/icu/source/tools/gen
+       echo "${CC} ${CFLAGS} ${CPPFLAGS} ${LDFLAGS}"
        case "${CC} ${CFLAGS} ${CPPFLAGS} ${LDFLAGS}" in  #(
-         *-arch*ppc*|*-arch*i386*|*-arch*x86_64*) ac_cv_c_bigendian=universal;;
-+        *-arch*i386*|*-arch*x86_64*) ac_cv_c_bigendian=no;;
++        *-arch*i386*|*-arch*x86_64*|*-arch*arm64*|*-arch*aarch64*) 
ac_cv_c_bigendian=no;;
+         *-arch*ppc*) ac_cv_c_bigendian=yes;;
        esac
  else
diff --git a/main/jvmfwk/plugins/sunmajor/pluginlib/util.cxx 
b/main/jvmfwk/plugins/sunmajor/pluginlib/util.cxx
index daec7fe94a..fbeb1ef201 100644
--- a/main/jvmfwk/plugins/sunmajor/pluginlib/util.cxx
+++ b/main/jvmfwk/plugins/sunmajor/pluginlib/util.cxx
@@ -102,6 +102,12 @@ struct JavaSearchPathEntry {
struct JavaSearchPathEntry g_arSearchPaths[] = {
#ifdef MACOSX
     { 0, "" },
+    // Modern macOS JDK location (Oracle/Temurin/etc., both arm64 and x86_64
+    // install here). Each subdirectory is a JDK whose home is Contents/Home,
+    // so scan the immediate contents. A JDK of the wrong architecture (e.g. a
+    // Rosetta x86_64 JDK on Apple Silicon) is harmlessly skipped when its
+    // libjvm.dylib fails to load into the native-arch process.
+    { 1, "Library/Java/JavaVirtualMachines/" },
     { 0, "Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin" 
},
     { 0, "System/Library/Frameworks/JavaVM.framework/Versions/1.4.2/" },
#else
@@ -1245,6 +1251,14 @@ void createJavaInfoDirScan(vector<rtl::Reference<VendorBase> 
>& vecInfos)
                                    OUSTR(" is a Java. \n"));

                         getJREInfoByPath(aStatus.getFileURL(),vecInfos);
+#ifdef MACOSX
+                        // On macOS a JDK bundle's home is at 
<bundle>/Contents/Home
+                        // (e.g. under 
/Library/Java/JavaVirtualMachines/<jdk>/),
+                        // not the bundle directory itself, so also probe 
there.
+                        getJREInfoByPath(
+                            aStatus.getFileURL() +
+                            OUSTR("/Contents/Home"), vecInfos);
+#endif
                     }

                     JFW_ENSURE(errNext == File::E_None || errNext == 
File::E_NOENT,
diff --git a/main/openssl/makefile.mk b/main/openssl/makefile.mk
index cecba9e26e..a5662eabea 100644
--- a/main/openssl/makefile.mk
+++ b/main/openssl/makefile.mk
@@ -107,8 +107,12 @@ UNAME=$(shell uname)
.ENDIF

.IF "$(OS)" == "MACOSX"
+.IF "$(CPUNAME)" == "AARCH64"
+       CONFIGURE_ACTION=Configure darwin64-arm64-cc no-dso no-shared $(NO_ASM)
+.ELSE
        CONFIGURE_ACTION=Configure darwin64-x86_64-cc no-dso no-shared $(NO_ASM)
.ENDIF
+.ENDIF

.IF "$(OS)" == "WNT"

diff --git a/main/python/pyversion.mk b/main/python/pyversion.mk
index 353925e92e..95f7b299da 100644
--- a/main/python/pyversion.mk
+++ b/main/python/pyversion.mk
@@ -20,8 +20,8 @@
# *************************************************************
# when you want to change the python version, you must update the d.lst
# in the python project accordingly !!!
-PYMAJOR=2
-PYMINOR=7
+PYMAJOR=3
+PYMINOR=10
PYMICRO=18
PYVERSION=$(PYMAJOR).$(PYMINOR).$(PYMICRO)

diff --git a/main/python/pyversion_dmake.mk b/main/python/pyversion_dmake.mk
index 37aa099277..b8252a9767 100644
--- a/main/python/pyversion_dmake.mk
+++ b/main/python/pyversion_dmake.mk
@@ -20,8 +20,8 @@
# *************************************************************
# when you want to change the python version, you must update the d.lst
# in the python project accordingly !!!
-PYMAJOR=2
-PYMINOR=7
+PYMAJOR=3
+PYMINOR=10
PYMICRO=18
PYVERSION=$(PYMAJOR).$(PYMINOR).$(PYMICRO)

diff --git a/main/pyuno/source/loader/pythonloader.py 
b/main/pyuno/source/loader/pythonloader.py
index 46e051da98..34ff1c532b 100644
--- a/main/pyuno/source/loader/pythonloader.py
+++ b/main/pyuno/source/loader/pythonloader.py
@@ -21,7 +21,7 @@
import uno
import unohelper
import sys
-import imp
+import types
import os
from com.sun.star.uno import Exception,RuntimeException
from com.sun.star.loader import XImplementationLoader
@@ -84,14 +84,14 @@ class Loader( XImplementationLoader, XServiceInfo, 
unohelper.Base ):
                 # did we load the module already ?
                 mod = g_loadedComponents.get( url )
                 if not mod:
-                    mod = imp.new_module("uno_component")
+                    mod = types.ModuleType("uno_component")

                     # check for pythonpath.zip beside .py files
                     checkForPythonPathBesideComponent( url[0:url.rfind('/')] )

                     # read the file
                     filename = unohelper.fileUrlToSystemPath( url )
-                    fileHandle = file( filename )
+                    fileHandle = open( filename )
                     src = fileHandle.read().replace("\r","")
                     if not src.endswith( "\n" ):
                         src = src + "\n"
diff --git a/main/sal/osl/unx/interlck.c b/main/sal/osl/unx/interlck.c
index cfcea0fbc0..d24db7b341 100644
--- a/main/sal/osl/unx/interlck.c
+++ b/main/sal/osl/unx/interlck.c
@@ -178,6 +178,29 @@ oslInterlockedCount SAL_CALL 
osl_decrementInterlockedCount(oslInterlockedCount*
#endif
}

+#elif (defined(__GNUC__) || defined(__clang__)) && defined ( AARCH64 )
+/* AArch64 (ARM 64-bit, e.g. Apple Silicon). Use the compiler's atomic
+   built-ins, which clang/gcc lower to the AArch64 
load-exclusive/store-exclusive
+   (ldaxr/stlxr) sequence, or to LSE atomics (ldadd) on ARMv8.1+. This avoids 
the
+   global-mutex fallback below. __sync_*_and_fetch are full-barrier and return
+   the new value, matching the required semantics. */
+
+/*****************************************************************************/
+/* osl_incrementInterlockedCount */
+/*****************************************************************************/
+oslInterlockedCount SAL_CALL 
osl_incrementInterlockedCount(oslInterlockedCount* pCount)
+{
+    return __sync_add_and_fetch( pCount, 1 );
+}
+
+/*****************************************************************************/
+/* osl_decrementInterlockedCount */
+/*****************************************************************************/
+oslInterlockedCount SAL_CALL 
osl_decrementInterlockedCount(oslInterlockedCount* pCount)
+{
+    return __sync_sub_and_fetch( pCount, 1 );
+}
+
#else
/* use only if nothing else works, expensive due to single mutex for all 
reference counts */

diff --git a/main/sal/rtl/source/macro.hxx b/main/sal/rtl/source/macro.hxx
index 10948868f3..4aee4358aa 100644
--- a/main/sal/rtl/source/macro.hxx
+++ b/main/sal/rtl/source/macro.hxx
@@ -77,6 +77,8 @@ this is inserted for the case that the preprocessor ignores 
error
#    else
#        define THIS_ARCH "MIPS_EL"
#    endif
+#elif defined AARCH64
+#    define THIS_ARCH "AARCH64"
#elif defined ARM
#    ifdef __ARM_EABI__
#        define THIS_ARCH "ARM_EABI"
diff --git a/main/scripting/source/pyprov/mailmerge.py 
b/main/scripting/source/pyprov/mailmerge.py
index 4a4c430c28..c11ddd8c7a 100644
--- a/main/scripting/source/pyprov/mailmerge.py
+++ b/main/scripting/source/pyprov/mailmerge.py
@@ -54,13 +54,13 @@ from com.sun.star.lang import IllegalArgumentException
from com.sun.star.lang import EventObject
from com.sun.star.mail import SendMailMessageFailedException

-from email.MIMEBase import MIMEBase
-from email.Message import Message
-from email import Encoders
-from email.Header import Header
-from email.MIMEMultipart import MIMEMultipart
-from email.Utils import formatdate
-from email.Utils import parseaddr
+from email.mime.base import MIMEBase
+from email.message import Message
+from email import encoders
+from email.header import Header
+from email.mime.multipart import MIMEMultipart
+from email.utils import formatdate
+from email.utils import parseaddr
from socket import _GLOBAL_DEFAULT_TIMEOUT

import sys, smtplib, imaplib, poplib
@@ -245,7 +245,7 @@ class PyMailSMTPService(unohelper.Base, XSmtpService):
             msgattachment = MIMEBase(maintype, subtype)
             data = content.getTransferData(flavor)
             msgattachment.set_payload(data)
-            Encoders.encode_base64(msgattachment)
+            encoders.encode_base64(msgattachment)
             fname = attachment.ReadableName
             try:
                 fname.encode('ascii')
diff --git a/main/scripting/source/pyprov/pythonscript.py 
b/main/scripting/source/pyprov/pythonscript.py
index 4e7fc4667e..03f52b897a 100644
--- a/main/scripting/source/pyprov/pythonscript.py
+++ b/main/scripting/source/pyprov/pythonscript.py
@@ -24,7 +24,7 @@ import uno
import unohelper
import sys
import os
-import imp
+import types
import time
import ast

@@ -356,7 +356,7 @@ class ScriptContext(unohelper.Base):
#        code = readTextFromStream( sfa.openFileRead( url ) )

         # execute the module
-#        entry = ModuleEntry( lastRead, imp.new_module("ooo_script_framework") 
)
+#        entry = ModuleEntry( lastRead, 
types.ModuleType("ooo_script_framework") )
#        entry.module.__dict__[GLOBAL_SCRIPTCONTEXT_NAME] = g_scriptContext
#        entry.module.__file__ = url
#        exec code in entry.module.__dict__
@@ -489,7 +489,7 @@ class ProviderContext:
             src = ensureSourceState( src )

             # execute the module
-            entry = ModuleEntry( lastRead, 
imp.new_module("ooo_script_framework") )
+            entry = ModuleEntry( lastRead, 
types.ModuleType("ooo_script_framework") )
             entry.module.__dict__[GLOBAL_SCRIPTCONTEXT_NAME] = 
self.scriptContext

             code = None
@@ -666,7 +666,7 @@ class ScriptBrowseNode( unohelper.Base, XBrowseNode, 
XPropertySet, XInvocation,
             if event.ActionCommand == "Run":
                 code = self.editor.getControl("EditorTextField").getText()
                 code = ensureSourceState( code )
-                mod = imp.new_module("ooo_script_framework")
+                mod = types.ModuleType("ooo_script_framework")
                 mod.__dict__[GLOBAL_SCRIPTCONTEXT_NAME] = 
self.provCtx.scriptContext
                 exec(code, mod.__dict__)
                 values = mod.__dict__.get( CALLABLE_CONTAINER_NAME , None )
@@ -827,7 +827,7 @@ class FileBrowseNode( unohelper.Base, XBrowseNode, 
XPropertySet, XInvocation, XA
             if event.ActionCommand == "Run":
                 code = self.editor.getControl("EditorTextField").getText()
                 code = ensureSourceState( code )
-                mod = imp.new_module("ooo_script_framework")
+                mod = types.ModuleType("ooo_script_framework")
                 mod.__dict__[GLOBAL_SCRIPTCONTEXT_NAME] = 
self.provCtx.scriptContext
                 exec(code, mod.__dict__)
                 values = mod.__dict__.get( CALLABLE_CONTAINER_NAME , None )
diff --git a/main/set_soenv.in b/main/set_soenv.in
index 189b6afdfe..6812905f8e 100644
--- a/main/set_soenv.in
+++ b/main/set_soenv.in
@@ -807,6 +807,14 @@ elsif ( $platform =~ m/darwin/ )
           $CPUNAME        = "X86_64";
           $OUTPATH        = "unxmaccx";
       }
+      elsif ($platform =~ m/^(aarch64|arm64)/)
+      {
+          print "Setting values for MacOSX/Darwin on aarch64 (Apple Silicon)... 
";
+          $outfile        = "MacOSXAARCH64Env.Set";
+          $CPU            = "R";
+          $CPUNAME        = "AARCH64";
+          $OUTPATH        = "unxmaccr";
+      }
       else
       {
          print "\nset_soenv: Unknown MacOSX/Darwin platform: $platform\n";
diff --git a/main/setup_native/source/mac/Info.plist.langpack 
b/main/setup_native/source/mac/Info.plist.langpack
index 0e12cc1c19..80ad91f30b 100644
--- a/main/setup_native/source/mac/Info.plist.langpack
+++ b/main/setup_native/source/mac/Info.plist.langpack
@@ -23,7 +23,7 @@
<plist version="1.0">
<dict>
        <key>LSMinimumSystemVersion</key>
-       <string>10.7.0</string>
+       <string>11.0</string>
        <key>CFBundleDevelopmentRegion</key>
        <string>English</string>
        <!-- UTI declarations for OS X >= 10.4    -->
diff --git a/main/solenv/bin/modules/installer/download.pm 
b/main/solenv/bin/modules/installer/download.pm
index 6605bbdbc6..6ad1570ab0 100644
--- a/main/solenv/bin/modules/installer/download.pm
+++ b/main/solenv/bin/modules/installer/download.pm
@@ -607,6 +607,10 @@ sub get_download_architecture
        {
                $arch = "x86-64";
        }
+       elsif ( $installer::globals::compiler =~ /^unxmaccr/ )
+       {
+               $arch = "aarch64";
+       }
        elsif ( $installer::globals::issolarissparcbuild )
        {
                $arch = "Sparc";
diff --git a/main/solenv/bin/modules/installer/worker.pm 
b/main/solenv/bin/modules/installer/worker.pm
index 0d387a3e33..ef22a34e2a 100644
--- a/main/solenv/bin/modules/installer/worker.pm
+++ b/main/solenv/bin/modules/installer/worker.pm
@@ -2280,6 +2280,10 @@ sub get_platform_name
        {
                $platformname = "MacOSXX86-64";
        }
+       elsif ( $installer::globals::compiler =~ /^unxmaccr/ )
+       {
+               $platformname = "MacOSXAArch64";
+       }
        elsif ( $installer::globals::compiler =~ /^unxmacxp/ )
        {
                $platformname = "MacOSXPowerPC";
diff --git a/main/solenv/bin/modules/osarch.pm 
b/main/solenv/bin/modules/osarch.pm
index 4ded37ed15..1093b81a27 100644
--- a/main/solenv/bin/modules/osarch.pm
+++ b/main/solenv/bin/modules/osarch.pm
@@ -102,7 +102,9 @@ chop( $m_str, $s_str );
                           "IP22",          "mips",         # voyager
                           "IP32",          "mips",         # giotto
                           "Power Macintosh",                 "ppc",            
            # NetBSD/arm32
-                          "arm32",                   "arm32"                   
    # NetBSD/arm32
+                          "arm32",                   "arm32",              # 
NetBSD/arm32
+                          "arm64",                   "aarch64",            # 
macOS Apple Silicon (uname -m)
+                          "aarch64",         "aarch64"             # Linux 
aarch64
                           );

%archDefTable=("sun4c",                       "-DSPARC -DSUN -DSUN4",       # 
hawai
@@ -130,7 +132,9 @@ chop( $m_str, $s_str );
                           "IP22",          "-DMIPS",                       # 
voyager
                           "IP32",          "-DMIPS",                       # 
giotto
                           "Power Macintosh",         "-DPPC",              # 
NetBSD/arm32
-                          "arm32",                   "-DARM32"             # 
NetBSD/arm32
+                          "arm32",                   "-DARM32",            # 
NetBSD/arm32
+                          "arm64",                   "-DAARCH64",          # 
macOS Apple Silicon (uname -m)
+                          "aarch64",         "-DAARCH64"           # Linux 
aarch64
                           );

%archDosTable=("sun4c",                       "s",          # hawai
@@ -158,7 +162,9 @@ chop( $m_str, $s_str );
                           "IP22",          "m",            # voyager
                           "IP32",          "m",            # giotto
                           "Power Macintosh",                 "p",              
    # NetBSD/arm32
-                          "arm32",                   "a"                   # 
NetBSD/arm32
+                          "arm32",                   "a",                  # 
NetBSD/arm32
+                          "arm64",                   "r",                  # 
macOS Apple Silicon (uname -m)
+                          "aarch64",         "r"                   # Linux 
aarch64
                           );

$main::solarDef         = $osDefTable{ $s_str }.' '.$archDefTable{ $m_str };
diff --git a/main/solenv/bin/update_module_ignore_lists.pl 
b/main/solenv/bin/update_module_ignore_lists.pl
index 3a827d743f..f7eecef05d 100644
--- a/main/solenv/bin/update_module_ignore_lists.pl
+++ b/main/solenv/bin/update_module_ignore_lists.pl
@@ -47,6 +47,7 @@ my @platforms = (
         "unxmacxp",
         "unxmacci",
         "unxmaccx",
+        "unxmaccr",
         "unxubit8",
         "unxaixp",
         "unxbsda",
diff --git a/main/solenv/gbuild/platform/macosx.mk 
b/main/solenv/gbuild/platform/macosx.mk
index 3b5d65805a..b9501be453 100644
--- a/main/solenv/gbuild/platform/macosx.mk
+++ b/main/solenv/gbuild/platform/macosx.mk
@@ -64,6 +64,8 @@ ifeq ($(CPUNAME),POWERPC)
gb_CPUDEFS += -DPOWERPC -DPPC
else ifeq ($(CPUNAME),INTEL)
gb_CPUDEFS += -DX86
+else ifeq ($(CPUNAME),AARCH64)
+gb_CPUDEFS += -DARM64
endif

ifeq ($(strip $(SYSBASE)),)
diff --git a/main/solenv/inc/unx.mk b/main/solenv/inc/unx.mk
index f956e43a82..b5b4731cd6 100644
--- a/main/solenv/inc/unx.mk
+++ b/main/solenv/inc/unx.mk
@@ -160,6 +160,10 @@
.INCLUDE : unxmaccx.mk
.ENDIF

+.IF "$(COM)$(OS)$(CPU)" == "CLANGMACOSXR"
+.INCLUDE : unxmaccr.mk
+.ENDIF
+
.IF "$(OS)$(CPU)" == "LINUXM"
.INCLUDE : unxlngmips.mk
.ENDIF
diff --git a/main/solenv/inc/unxmaccr.mk b/main/solenv/inc/unxmaccr.mk
new file mode 100644
index 0000000000..0fdf36cc2d
--- /dev/null
+++ b/main/solenv/inc/unxmaccr.mk
@@ -0,0 +1,42 @@
+#**************************************************************
+#
+#  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
+#
+#  Unless required by applicable law or agreed to in writing,
+#  software distributed under the License is distributed on an
+#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+#  specific language governing permissions and limitations
+#  under the License.
+#
+#**************************************************************
+
+# Mac OSX aarch64 (Apple Silicon) specific defines
+
+PROCESSOR_DEFINES=-DAARCH64
+BUILD64=1
+
+DLLPOSTFIX=
+
+# Build explicitly for arm64. Use conditional assignment (*=) so the value can
+# still be overridden by exporting ARCH_FLAGS in the environment. unxmacc.mk
+# also declares ARCH_FLAGS*= (empty), which becomes a no-op once set here.
+ARCH_FLAGS*=-arch arm64
+
+# flags to enable build with symbols; required by crashdump feature
+.IF "$(ENABLE_SYMBOLS)"=="SMALL"
+CFLAGSENABLESYMBOLS=-g1
+.ELSE
+CFLAGSENABLESYMBOLS=-g
+.ENDIF
+
+# Include generic Mac OS X makefile
+.INCLUDE : unxmacc.mk
diff --git a/main/source_soenv.sh b/main/source_soenv.sh
index 9d522c359f..ce87621c36 100644
--- a/main/source_soenv.sh
+++ b/main/source_soenv.sh
@@ -108,6 +108,9 @@ else
         i[3456]86-*-darwin*|x86_64-*-darwin*)
             . ./MacOSXX64Env.Set.sh
         ;;
+        aarch64-*-darwin*|arm64-*-darwin*)
+            . ./MacOSXAARCH64Env.Set.sh
+        ;;
         powerpc-*-darwin*)
             . ./MacOSXPPCEnv.Set.sh
         ;;
diff --git a/main/sysui/desktop/macosx/Info.plist 
b/main/sysui/desktop/macosx/Info.plist
index d26d4251fe..9ffda6b8fa 100644
--- a/main/sysui/desktop/macosx/Info.plist
+++ b/main/sysui/desktop/macosx/Info.plist
@@ -23,7 +23,7 @@
<plist version="1.0">
<dict>
        <key>LSMinimumSystemVersion</key>
-       <string>10.7.0</string>
+       <string>11.0</string>
        <key>CFBundleDevelopmentRegion</key>
        <string>English</string>
        <!-- UTI declarations for OS X >= 10.4    -->


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to