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 -->