There is still lots to do w/ the Python3 stuff. This also changes the thing for macOS baseline: We have to bump up to BigSur being the oldest supported version, and even then we might even need to go newer as I dig more into it. The key isn't just Aarch64 support but also the oldest version of Xcode that _knows_ about Apple Silicon!
Still. Progress. > On Jun 5, 2026, at 12:16 PM, [email protected] wrote: > > Awesome Job! this is a great step. Highly appreciated on my side. > > > > Am 05.06.2026 um 17:12 schrieb Dave Fisher: >> I want to highlight the two hugely important contributions in this commit. >> >> 1. Native Apple Silicon support. >> 2. Python 3.10 support. >> >> A big thanks to Jim! >> >> Best, >> Dave >> >>> On Jun 5, 2026, at 8:46 AM, [email protected] wrote: >>> >>> This is an automated email from the ASF dual-hosted git repository. >>> >>> jimjag pushed a commit to branch trunk >>> in repository https://gitbox.apache.org/repos/asf/openoffice.git >>> >>> >>> The following commit(s) were added to refs/heads/trunk by this push: >>> new 5e139d9fe4 Native Apple Silicon (arm64) support and bundled Python >>> 3.10 baseline >>> 5e139d9fe4 is described below >>> >>> commit 5e139d9fe42a654147771da4118aea6285c03168 >>> Author: Jim Jagielski <[email protected]> >>> AuthorDate: Fri Jun 5 09:44:36 2026 -0400 >>> >>> Native Apple Silicon (arm64) support and bundled Python 3.10 baseline >>> >>> Squashed combination of two efforts, applied onto trunk as a single >>> commit. (trunk is not intended to be buildable; this lands the work for >>> reference/integration.) >>> >>> === Apple Silicon (macOS arm64 / AAPCS64) === >>> Build plumbing: set_soenv.in + source_soenv.sh arm64 Darwin branch >>> (CPU=R, CPUNAME=AARCH64, OUTPATH=unxmaccr); new solenv/inc/unxmaccr.mk >>> and unx.mk dispatch; macro.hxx AARCH64 arch string; osarch.pm + >>> gbuild/platform/macosx.mk arch entries; configure.ac arm64 host >>> detection, Big Sur+ version math, and 11.0 deployment target. >>> >>> C++/UNO bridge (new s5abi_macosx_aarch64): abi.cxx/hxx AAPCS64 classifier >>> (HFA + <=16B/>16B size rules), uno2cpp + call.s AArch64 trampoline, >>> cpp2uno incoming path + privateSnippetExecutor + AArch64 codeSnippet >>> codegen (x8 indirect-result handled, not displacing this/x0), share.hxx >>> __cxa_exception reserved-member alignment fix; Library_cpp_uno.mk + >>> makefile.mk wiring. sal/osl/unx/interlck.c arm64 atomics (__sync_* -> >>> LSE). >>> >>> Externals: openssl darwin64-arm64-cc; icu arm64 little-endian. (NSS 3.39 >>> deferred -- too old for arm64.) >>> >>> Packaging/JVM: Info.plist LSMinimumSystemVersion 11.0; installer >>> download.pm/worker.pm/update_module_ignore_lists.pl recognize unxmaccr; >>> jvmfwk modern macOS JDK discovery (/Library/Java/JavaVirtualMachines + >>> Contents/Home probe). >>> >>> The ABI/atomics/trampoline/JDK-discovery code was unit-tested natively >>> on an arm64 macOS host; a full AOO build (and bridgetest) was not run. >>> Code-signing infra (mandatory for arm64 distribution) is NOT included. >>> >>> === Bundled Python 2.7.18 -> 3.10 baseline (Unix/macOS first) === >>> pyversion.mk/_dmake.mk -> 3.10.18 (single version knob). Shipped .py >>> fixes: imp -> types.ModuleType (pythonscript.py, pythonloader.py) and >>> file() -> open(); mailmerge.py Py3 email module imports + encoders. >>> Windows Python 3 build and the makefile.mk/d.lst/configure.ac Py3 work >>> are NOT included (separate, larger effort). >>> >>> NOTE: macOS 11 becomes the minimum supported version. Python 3.10 is >>> EOL 2026-10; the version knob allows a later bump. >>> --- >>> main/bridges/Library_cpp_uno.mk | 18 + >>> .../source/cpp_uno/s5abi_macosx_aarch64/abi.cxx | 261 +++++++++ >>> .../source/cpp_uno/s5abi_macosx_aarch64/abi.hxx | 86 +++ >>> .../source/cpp_uno/s5abi_macosx_aarch64/call.s | 168 ++++++ >>> .../cpp_uno/s5abi_macosx_aarch64/cpp2uno.cxx | 543 +++++++++++++++++++ >>> .../source/cpp_uno/s5abi_macosx_aarch64/except.cxx | 358 +++++++++++++ >>> .../cpp_uno/s5abi_macosx_aarch64/makefile.mk | 81 +++ >>> .../source/cpp_uno/s5abi_macosx_aarch64/share.hxx | 116 ++++ >>> .../cpp_uno/s5abi_macosx_aarch64/uno2cpp.cxx | 581 >>> +++++++++++++++++++++ >>> main/configure.ac | 42 +- >>> main/icu/icu4c-4_2_1-src.patch | 2 +- >>> main/jvmfwk/plugins/sunmajor/pluginlib/util.cxx | 14 + >>> main/openssl/makefile.mk | 4 + >>> main/python/pyversion.mk | 4 +- >>> main/python/pyversion_dmake.mk | 4 +- >>> main/pyuno/source/loader/pythonloader.py | 6 +- >>> main/sal/osl/unx/interlck.c | 23 + >>> main/sal/rtl/source/macro.hxx | 2 + >>> main/scripting/source/pyprov/mailmerge.py | 16 +- >>> main/scripting/source/pyprov/pythonscript.py | 10 +- >>> main/set_soenv.in | 8 + >>> main/setup_native/source/mac/Info.plist.langpack | 2 +- >>> main/solenv/bin/modules/installer/download.pm | 4 + >>> main/solenv/bin/modules/installer/worker.pm | 4 + >>> main/solenv/bin/modules/osarch.pm | 12 +- >>> main/solenv/bin/update_module_ignore_lists.pl | 1 + >>> main/solenv/gbuild/platform/macosx.mk | 2 + >>> main/solenv/inc/unx.mk | 4 + >>> main/solenv/inc/unxmaccr.mk | 42 ++ >>> main/source_soenv.sh | 3 + >>> main/sysui/desktop/macosx/Info.plist | 2 +- >>> 31 files changed, 2391 insertions(+), 32 deletions(-) >>> >>> diff --git a/main/bridges/Library_cpp_uno.mk >>> b/main/bridges/Library_cpp_uno.mk >>> index d868df954f..0d8525362a 100644 >>> --- a/main/bridges/Library_cpp_uno.mk >>> +++ b/main/bridges/Library_cpp_uno.mk >>> @@ -431,6 +431,24 @@ $(eval $(call >>> gb_Library_add_exception_objects,$(COMNAME)_uno,\ >>> bridges/source/cpp_uno/s5abi_macosx_x86-64/uno2cpp \ >>> )) >>> >>> +########################################################### >>> +else ifeq ($(OS)-$(CPUNAME)-$(COMNAME),MACOSX-AARCH64-s5abi) >>> +########################################################### >>> +# Apple Silicon (arm64) bridge. The COMNAME is "s5abi" macOS-wide (set in >>> +# solenv/gbuild/platform/macosx.mk); for arm64 the actual calling >>> convention >>> +# is AAPCS64, so "s5abi" here is a historical label, not a literal ABI >>> claim. >>> + >>> +$(eval $(call gb_Library_add_exception_objects,$(COMNAME)_uno,\ >>> + bridges/source/cpp_uno/s5abi_macosx_aarch64/abi \ >>> + bridges/source/cpp_uno/s5abi_macosx_aarch64/except \ >>> + bridges/source/cpp_uno/s5abi_macosx_aarch64/cpp2uno \ >>> + bridges/source/cpp_uno/s5abi_macosx_aarch64/uno2cpp \ >>> +)) >>> + >>> +$(eval $(call gb_Library_add_asmobjects,$(COMNAME)_uno,\ >>> + bridges/source/cpp_uno/s5abi_macosx_aarch64/call \ >>> +)) >>> + >>> ######################################################### >>> else ifeq ($(OS)-$(CPUNAME)-$(COMNAME),NETBSD-INTEL-gcc3) >>> ######################################################### >>> diff --git a/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/abi.cxx >>> b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/abi.cxx >>> new file mode 100644 >>> index 0000000000..d51c5ccf12 >>> --- /dev/null >>> +++ b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/abi.cxx >>> @@ -0,0 +1,261 @@ >>> +/************************************************************** >>> + * >>> + * Licensed to the Apache Software Foundation (ASF) under one >>> + * or more contributor license agreements. See the NOTICE file >>> + * distributed with this work for additional information >>> + * regarding copyright ownership. The ASF licenses this file >>> + * to you under the Apache License, Version 2.0 (the >>> + * "License"); you may not use this file except in compliance >>> + * with the License. You may obtain a copy of the License at >>> + * >>> + * http://www.apache.org/licenses/LICENSE-2.0 >>> + * >>> + * Unless required by applicable law or agreed to in writing, >>> + * software distributed under the License is distributed on an >>> + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY >>> + * KIND, either express or implied. See the License for the >>> + * specific language governing permissions and limitations >>> + * under the License. >>> + * >>> + *************************************************************/ >>> + >>> + >>> + >>> +// MARKER(update_precomp.py): autogen include statement, do not remove >>> +#include "precompiled_bridges.hxx" >>> + >>> +// This is an implementation of the parameter-classification rules of the >>> +// AArch64 procedure call standard ("Procedure Call Standard for the Arm >>> 64-bit >>> +// Architecture", ARM IHI 0055), with the deviations documented in Apple's >>> +// "Writing ARM64 Code for Apple Platforms". >>> +// >>> +// Unlike the System V AMD64 ABI (used by the x86-64 bridge), AAPCS64 does >>> not >>> +// split aggregates into per-eightbyte INTEGER/SSE classes. Instead: >>> +// * scalars go in one GPR (x) or one FP/SIMD (v) register; >>> +// * a Homogeneous Floating-point Aggregate (HFA: <= 4 members, all the >>> same >>> +// FP type, recursively) goes in consecutive v registers; >>> +// * any other aggregate <= 16 bytes goes in 1-2 GPRs; >>> +// * a non-HFA aggregate > 16 bytes is passed indirectly (a pointer to a >>> +// caller-allocated copy). >>> +// Register fill is "all or nothing": if an aggregate does not fit >>> entirely in >>> +// the remaining registers of its bank, it is passed wholly on the stack. >>> +// >>> +// This is a clean-room implementation from the public specifications; see >>> +// ../../../../AAPCS64_BRIDGE_SPEC.md. libffi's aarch64 backend was >>> consulted >>> +// only as a behavioural reference; no code is copied. >>> + >>> +#include "abi.hxx" >>> + >>> +#include <rtl/ustring.hxx> >>> + >>> +using namespace aarch64; >>> + >>> +namespace { >>> + >>> +// The element type of a Homogeneous Floating-point Aggregate. >>> +enum HfaKind >>> +{ >>> + HFA_NONE, // not (yet) an HFA >>> + HFA_FLOAT, // all members are FLOAT (4-byte) >>> + HFA_DOUBLE // all members are DOUBLE (8-byte) >>> +}; >>> + >>> +// Combine the running HFA kind with a newly-seen member kind. Two members >>> +// of different FP types, or any non-FP member, break the homogeneity. >>> +HfaKind mergeHfa( HfaKind running, HfaKind seen ) >>> +{ >>> + if ( seen == HFA_NONE ) >>> + return HFA_NONE; >>> + if ( running == HFA_NONE ) >>> + return seen; >>> + return ( running == seen ) ? running : HFA_NONE; >>> +} >>> + >>> +// Recursively determine whether pTypeRef is (part of) a homogeneous >>> +// floating-point aggregate, accumulating the element kind and member >>> count. >>> +// >>> +// Returns false the moment homogeneity is violated (a non-FP scalar, or a >>> +// second distinct FP type, or > 4 elements). A FLOAT/DOUBLE scalar >>> counts as >>> +// a 1-element HFA of itself; a struct flattens its members (and base >>> classes). >>> +bool collectHfa( typelib_TypeDescriptionReference *pTypeRef, HfaKind >>> &rKind, int &rCount ) >>> +{ >>> + switch ( pTypeRef->eTypeClass ) >>> + { >>> + case typelib_TypeClass_FLOAT: >>> + rKind = mergeHfa( rKind, HFA_FLOAT ); >>> + if ( rKind == HFA_NONE ) return false; >>> + return ( ++rCount <= 4 ); >>> + >>> + case typelib_TypeClass_DOUBLE: >>> + rKind = mergeHfa( rKind, HFA_DOUBLE ); >>> + if ( rKind == HFA_NONE ) return false; >>> + return ( ++rCount <= 4 ); >>> + >>> + case typelib_TypeClass_STRUCT: >>> + case typelib_TypeClass_EXCEPTION: >>> + { >>> + typelib_TypeDescription * pTypeDescr = 0; >>> + TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef ); >>> + >>> + const typelib_CompoundTypeDescription *pComp = >>> + reinterpret_cast<const typelib_CompoundTypeDescription*>( >>> pTypeDescr ); >>> + >>> + bool bOk = true; >>> + >>> + // Flatten base class first (its members precede ours in >>> layout). >>> + if ( pComp->pBaseTypeDescription ) >>> + { >>> + bOk = collectHfa( >>> + pComp->pBaseTypeDescription->aBase.pWeakRef, rKind, >>> rCount ); >>> + } >>> + >>> + for ( sal_Int32 i = 0; bOk && i < pComp->nMembers; ++i ) >>> + bOk = collectHfa( pComp->ppTypeRefs[i], rKind, rCount ); >>> + >>> + TYPELIB_DANGER_RELEASE( pTypeDescr ); >>> + return bOk; >>> + } >>> + >>> + default: >>> + // Any non-FP, non-aggregate member breaks homogeneity. >>> + rKind = HFA_NONE; >>> + return false; >>> + } >>> +} >>> + >>> +// Classify an aggregate (STRUCT/EXCEPTION). Sets the GPR/FPR counts and >>> +// returns true if it is passed in registers, false if it must be passed >>> +// indirectly (in memory). >>> +bool classifyAggregate( typelib_TypeDescriptionReference *pTypeRef, int >>> &nUsedGPR, int &nUsedFPR ) >>> +{ >>> + // First, the HFA test. >>> + HfaKind kind = HFA_NONE; >>> + int count = 0; >>> + if ( collectHfa( pTypeRef, kind, count ) && kind != HFA_NONE && count >>> >= 1 && count <= 4 ) >>> + { >>> + nUsedGPR = 0; >>> + nUsedFPR = count; // one v register per member >>> + return true; >>> + } >>> + >>> + // Otherwise classify by size. >>> + typelib_TypeDescription * pTypeDescr = 0; >>> + TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef ); >>> + sal_Int32 nSize = pTypeDescr->nSize; >>> + TYPELIB_DANGER_RELEASE( pTypeDescr ); >>> + >>> + if ( nSize > 16 ) >>> + { >>> + // Non-HFA aggregate > 16 bytes => passed indirectly. >>> + return false; >>> + } >>> + >>> + // Non-HFA aggregate <= 16 bytes => 1 or 2 GPRs (8 bytes each). >>> + nUsedGPR = ( nSize > 8 ) ? 2 : 1; >>> + nUsedFPR = 0; >>> + return true; >>> +} >>> + >>> +} // anonymous namespace >>> + >>> +bool aarch64::examine_argument( typelib_TypeDescriptionReference >>> *pTypeRef, bool /*bInReturn*/, int &nUsedGPR, int &nUsedFPR ) >>> +{ >>> + nUsedGPR = 0; >>> + nUsedFPR = 0; >>> + >>> + switch ( pTypeRef->eTypeClass ) >>> + { >>> + case typelib_TypeClass_VOID: >>> + return true; >>> + >>> + case typelib_TypeClass_CHAR: >>> + case typelib_TypeClass_BOOLEAN: >>> + case typelib_TypeClass_BYTE: >>> + case typelib_TypeClass_SHORT: >>> + case typelib_TypeClass_UNSIGNED_SHORT: >>> + case typelib_TypeClass_LONG: >>> + case typelib_TypeClass_UNSIGNED_LONG: >>> + case typelib_TypeClass_HYPER: >>> + case typelib_TypeClass_UNSIGNED_HYPER: >>> + case typelib_TypeClass_ENUM: >>> + nUsedGPR = 1; >>> + return true; >>> + >>> + case typelib_TypeClass_FLOAT: >>> + case typelib_TypeClass_DOUBLE: >>> + nUsedFPR = 1; >>> + return true; >>> + >>> + // These UNO types are always handled by the bridge as a pointer/ >>> + // reference (one GPR), never passed by value through this >>> classifier. >>> + case typelib_TypeClass_STRING: >>> + case typelib_TypeClass_TYPE: >>> + case typelib_TypeClass_ANY: >>> + case typelib_TypeClass_TYPEDEF: >>> + case typelib_TypeClass_SEQUENCE: >>> + case typelib_TypeClass_INTERFACE: >>> + nUsedGPR = 1; >>> + return true; >>> + >>> + case typelib_TypeClass_STRUCT: >>> + case typelib_TypeClass_EXCEPTION: >>> + return classifyAggregate( pTypeRef, nUsedGPR, nUsedFPR ); >>> + >>> + default: >>> +#if OSL_DEBUG_LEVEL > 1 >>> + OSL_TRACE( "Unhandled case: pTypeRef->eTypeClass == %d\n", >>> pTypeRef->eTypeClass ); >>> +#endif >>> + OSL_ASSERT( 0 ); >>> + } >>> + return false; >>> +} >>> + >>> +bool aarch64::return_in_hidden_param( typelib_TypeDescriptionReference >>> *pTypeRef ) >>> +{ >>> + int g, s; >>> + // Returned in registers iff examine_argument() says it fits; >>> otherwise the >>> + // caller must pass an indirect-result buffer in x8. >>> + return !examine_argument( pTypeRef, true, g, s ); >>> +} >>> + >>> +void aarch64::fill_struct( typelib_TypeDescriptionReference *pTypeRef, >>> const sal_uInt64 *pGPR, const double *pFPR, void *pStruct ) >>> +{ >>> + int nUsedGPR = 0; >>> + int nUsedFPR = 0; >>> + if ( !examine_argument( pTypeRef, true, nUsedGPR, nUsedFPR ) ) >>> + { >>> + // Should not happen: indirect returns are written through x8 >>> directly, >>> + // not scattered here. >>> + OSL_ASSERT( 0 ); >>> + return; >>> + } >>> + >>> + if ( nUsedFPR > 0 ) >>> + { >>> + // HFA: each member occupies one v register; the members are >>> contiguous >>> + // in the struct. Copy element-by-element to honour FLOAT >>> (4-byte) vs >>> + // DOUBLE (8-byte) element width. >>> + HfaKind kind = HFA_NONE; >>> + int count = 0; >>> + collectHfa( pTypeRef, kind, count ); >>> + if ( kind == HFA_FLOAT ) >>> + { >>> + float *pDest = reinterpret_cast<float *>( pStruct ); >>> + for ( int i = 0; i < nUsedFPR; ++i ) >>> + pDest[i] = static_cast<float>( pFPR[i] ); >>> + } >>> + else // HFA_DOUBLE >>> + { >>> + double *pDest = reinterpret_cast<double *>( pStruct ); >>> + for ( int i = 0; i < nUsedFPR; ++i ) >>> + pDest[i] = pFPR[i]; >>> + } >>> + } >>> + else >>> + { >>> + // Non-HFA aggregate <= 16 bytes: raw copy of the 1-2 GPRs. >>> + sal_uInt64 *pDest = reinterpret_cast<sal_uInt64 *>( pStruct ); >>> + for ( int i = 0; i < nUsedGPR; ++i ) >>> + pDest[i] = pGPR[i]; >>> + } >>> +} >>> diff --git a/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/abi.hxx >>> b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/abi.hxx >>> new file mode 100644 >>> index 0000000000..7d55ac076c >>> --- /dev/null >>> +++ b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/abi.hxx >>> @@ -0,0 +1,86 @@ >>> +/************************************************************** >>> + * >>> + * Licensed to the Apache Software Foundation (ASF) under one >>> + * or more contributor license agreements. See the NOTICE file >>> + * distributed with this work for additional information >>> + * regarding copyright ownership. The ASF licenses this file >>> + * to you under the Apache License, Version 2.0 (the >>> + * "License"); you may not use this file except in compliance >>> + * with the License. You may obtain a copy of the License at >>> + * >>> + * http://www.apache.org/licenses/LICENSE-2.0 >>> + * >>> + * Unless required by applicable law or agreed to in writing, >>> + * software distributed under the License is distributed on an >>> + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY >>> + * KIND, either express or implied. See the License for the >>> + * specific language governing permissions and limitations >>> + * under the License. >>> + * >>> + *************************************************************/ >>> + >>> + >>> + >>> +#ifndef _BRIDGES_CPP_UNO_AARCH64_ABI_HXX_ >>> +#define _BRIDGES_CPP_UNO_AARCH64_ABI_HXX_ >>> + >>> +// This is an implementation of the AArch64 procedure call standard, as >>> +// described in "Procedure Call Standard for the Arm 64-bit Architecture" >>> +// (ARM IHI 0055), with the deviations documented in Apple's "Writing ARM64 >>> +// Code for Apple Platforms". It is a clean-room implementation written >>> from >>> +// those public specifications; see ../../../../AAPCS64_BRIDGE_SPEC.md. >>> + >>> +#include <typelib/typedescription.hxx> >>> + >>> +namespace aarch64 >>> +{ >>> + >>> +/* 8 general purpose registers (x0..x7) are used for parameter passing. >>> + Note: the indirect-result-location register x8 is *separate* and is NOT >>> + part of this count. */ >>> +const sal_uInt32 MAX_GPR_REGS = 8; >>> + >>> +/* 8 SIMD/FP registers (v0..v7) are used for parameter passing. */ >>> +const sal_uInt32 MAX_FPR_REGS = 8; >>> + >>> +/* The largest number of registers a single aggregate can occupy: an >>> HFA/HVA >>> + may use up to 4 FP registers; a non-HFA aggregate passed in GPRs uses at >>> + most 2 (16 bytes / 8). */ >>> +const sal_uInt32 MAX_AGGREGATE_REGS = 4; >>> + >>> +/* Count the number of registers required to pass the given type. >>> + >>> + Examines the argument and sets the number of GPR (x) and FPR (v) >>> registers >>> + it would consume. For a Homogeneous Floating-point Aggregate the FPR >>> count >>> + is the number of members (<= 4); for a non-HFA aggregate <= 16 bytes >>> the GPR >>> + count is 1 or 2; scalars use exactly one register of the appropriate >>> bank. >>> + >>> + Returns false iff the parameter must be passed indirectly (in memory): a >>> + non-HFA aggregate larger than 16 bytes. When bInReturn is true the same >>> + classification answers "can this be returned in registers?" (false => >>> the >>> + caller must allocate a buffer and pass it in x8). >>> +*/ >>> +bool examine_argument( typelib_TypeDescriptionReference *pTypeRef, bool >>> bInReturn, int &nUsedGPR, int &nUsedFPR ); >>> + >>> +/** Does a function returning this type use the hidden indirect-result >>> pointer >>> + (passed by the caller in x8), or can it return in registers? >>> + >>> + A scalar returns in x0 or v0; an HFA returns in v0..v3; a non-HFA >>> aggregate >>> + of <= 16 bytes returns in x0,x1. Anything larger (non-HFA aggregate >>> + > 16 bytes) is returned via the caller-allocated buffer addressed by >>> x8 - >>> + that is the "hidden param" case, for which this returns true. >>> +*/ >>> +bool return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef ); >>> + >>> +/** Scatter a register-resident return value (an HFA returned in v0..v3, >>> or a >>> + non-HFA aggregate <= 16 bytes returned in x0,x1) into the caller's >>> struct. >>> + >>> + pGPR points at the saved x0,x1,... ; pFPR at the saved v0,v1,... (each >>> + element the low 8 bytes of a v register, i.e. a double slot). Only >>> valid >>> + when return_in_hidden_param() is false. >>> +*/ >>> +void fill_struct( typelib_TypeDescriptionReference *pTypeRef, const >>> sal_uInt64* pGPR, const double* pFPR, void *pStruct ); >>> + >>> +} // namespace aarch64 >>> + >>> +#endif // _BRIDGES_CPP_UNO_AARCH64_ABI_HXX_ >>> diff --git a/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/call.s >>> b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/call.s >>> new file mode 100644 >>> index 0000000000..035b38555a >>> --- /dev/null >>> +++ b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/call.s >>> @@ -0,0 +1,168 @@ >>> +/************************************************************** >>> + * >>> + * Licensed to the Apache Software Foundation (ASF) under one >>> + * or more contributor license agreements. See the NOTICE file >>> + * distributed with this work for additional information >>> + * regarding copyright ownership. The ASF licenses this file >>> + * to you under the Apache License, Version 2.0 (the >>> + * "License"); you may not use this file except in compliance >>> + * with the License. You may obtain a copy of the License at >>> + * >>> + * http://www.apache.org/licenses/LICENSE-2.0 >>> + * >>> + * Unless required by applicable law or agreed to in writing, >>> + * software distributed under the License is distributed on an >>> + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY >>> + * KIND, either express or implied. See the License for the >>> + * specific language governing permissions and limitations >>> + * under the License. >>> + * >>> + *************************************************************/ >>> + >>> +// AArch64 (Apple Silicon, AAPCS64) outgoing-call trampoline for the >>> C++-UNO >>> +// bridge. Loads the argument registers from caller-prepared arrays, >>> copies >>> +// any overflow arguments to the outgoing stack, performs the indirect >>> call, >>> +// and stores the integer and FP/SIMD return registers back. >>> +// >>> +// See AAPCS64_BRIDGE_SPEC.md. Mach-O assembler syntax; symbols are >>> prefixed >>> +// with an underscore per the Darwin C ABI. >>> +// >>> +// extern "C" void callVirtualFunction( >>> +// sal_uInt64 pFunction, // x0: target C++ virtual method >>> +// sal_uInt64 pIndirectRet, // x1: value for x8 (indirect result >>> ptr), 0 if none >>> +// sal_uInt64 *pGPR, // x2: 8 words -> x0..x7 >>> +// double *pFPR, // x3: 8 doubles -> d0..d7 >>> +// sal_uInt64 *pStack, // x4: overflow-arg words >>> +// sal_uInt32 nStackWords, // x5: number of 8-byte overflow words >>> +// sal_uInt64 *pGPRReturn, // x6: [out] x0,x1 >>> +// double *pFPRReturn); // x7: [out] d0..d3 (HFA up to 4 >>> elements) >>> + >>> + .text >>> + .globl _callVirtualFunction >>> + .p2align 2 >>> +_callVirtualFunction: >>> + // prologue: save fp/lr and the callee-saved registers we use >>> + stp x29, x30, [sp, #-16]! >>> + stp x19, x20, [sp, #-16]! >>> + stp x21, x22, [sp, #-16]! >>> + stp x23, x24, [sp, #-16]! >>> + mov x29, sp >>> + >>> + // stash inputs that must survive the call into callee-saved registers >>> + mov x19, x0 // pFunction >>> + mov x20, x2 // pGPR >>> + mov x21, x3 // pFPR >>> + mov x22, x6 // pGPRReturn >>> + mov x23, x7 // pFPRReturn >>> + mov x24, x1 // x8 indirect-result value >>> + >>> + // allocate and copy the outgoing overflow stack arguments. >>> + // bytes = ((nStackWords + 1) & ~1) * 8, to keep sp 16-byte aligned. >>> + add x9, x5, #1 >>> + bic x9, x9, #1 >>> + lsl x9, x9, #3 >>> + sub sp, sp, x9 >>> + mov x10, #0 >>> +Lcvf_copy: >>> + cmp x10, x5 >>> + b.ge Lcvf_copied >>> + ldr x11, [x4, x10, lsl #3] >>> + str x11, [sp, x10, lsl #3] >>> + add x10, x10, #1 >>> + b Lcvf_copy >>> +Lcvf_copied: >>> + >>> + // load the FP/SIMD argument registers d0..d7 >>> + ldp d0, d1, [x21, #0] >>> + ldp d2, d3, [x21, #16] >>> + ldp d4, d5, [x21, #32] >>> + ldp d6, d7, [x21, #48] >>> + >>> + // load the GP argument registers x0..x7 and the x8 indirect-result reg >>> + mov x8, x24 >>> + ldp x6, x7, [x20, #48] >>> + ldp x4, x5, [x20, #32] >>> + ldp x2, x3, [x20, #16] >>> + ldp x0, x1, [x20, #0] >>> + >>> + // perform the virtual call >>> + blr x19 >>> + >>> + // store the return registers >>> + str x0, [x22, #0] >>> + str x1, [x22, #8] >>> + str d0, [x23, #0] >>> + str d1, [x23, #8] >>> + str d2, [x23, #16] >>> + str d3, [x23, #24] >>> + >>> + // epilogue >>> + mov sp, x29 >>> + ldp x23, x24, [sp], #16 >>> + ldp x21, x22, [sp], #16 >>> + ldp x19, x20, [sp], #16 >>> + ldp x29, x30, [sp], #16 >>> + ret >>> + >>> +// >>> --------------------------------------------------------------------------- >>> +// privateSnippetExecutor: the incoming (cpp2uno) register-spill executor. >>> +// >>> +// Reached by a BR from a per-vtable-slot code snippet (see codeSnippet() >>> in >>> +// cpp2uno.cxx) with: >>> +// x16 = (nVtableOffset << 32) | nFunctionIndex (low bit 0x80000000 >>> flags a >>> +// hidden/indirect return) >>> +// x0..x7, d0..d7, x8 = the original incoming arguments (untouched) >>> +// sp = the caller's stack-argument area (overflow) >>> +// x30 = return address back into the original C++ caller >>> +// >>> +// It spills the argument registers to a save area and calls >>> cpp_vtable_call, >>> +// then loads the return value back into x0/x1 and d0/d1 (or d0 for fp). >>> +// >>> +// typelib_TypeClass cpp_vtable_call( >>> +// sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset, >>> +// void** gpreg, void** fpreg, void** ovrflw, >>> +// void* pIndirectReturn, sal_uInt64* pRegisterReturn); >>> +// >>> +// Frame (176 bytes): [0]=x29,x30 [16..79]=x0..x7 [80..143]=d0..d7 >>> +// [144..159]=return buffer. >>> + .globl _privateSnippetExecutor >>> + .p2align 2 >>> +_privateSnippetExecutor: >>> + mov x17, sp // x17 = ovrflw (incoming stack >>> args) >>> + stp x29, x30, [sp, #-176]! >>> + mov x29, sp >>> + >>> + stp x0, x1, [sp, #16] // save GP argument registers >>> x0..x7 >>> + stp x2, x3, [sp, #32] >>> + stp x4, x5, [sp, #48] >>> + stp x6, x7, [sp, #64] >>> + >>> + stp d0, d1, [sp, #80] // save FP/SIMD argument registers >>> d0..d7 >>> + stp d2, d3, [sp, #96] >>> + stp d4, d5, [sp, #112] >>> + stp d6, d7, [sp, #128] >>> + >>> + mov w0, w16 // nFunctionIndex (low 32 bits) >>> + lsr x1, x16, #32 // nVtableOffset (high 32 bits) >>> + add x2, sp, #16 // gpreg >>> + add x3, sp, #80 // fpreg >>> + mov x4, x17 // ovrflw >>> + mov x5, x8 // pIndirectReturn (x8 >>> indirect-result reg) >>> + add x6, sp, #144 // pRegisterReturn (16-byte buffer) >>> + bl _cpp_vtable_call >>> + >>> + cmp w0, #10 // typelib_TypeClass_FLOAT >>> + b.eq Lpse_float >>> + cmp w0, #11 // typelib_TypeClass_DOUBLE >>> + b.eq Lpse_float >>> + // integer / pointer / <=16B aggregate: load both banks; caller reads >>> the >>> + // ones that matter for its return type. >>> + ldp x0, x1, [sp, #144] >>> + ldp d0, d1, [sp, #144] >>> + b Lpse_done >>> +Lpse_float: >>> + ldr d0, [sp, #144] >>> +Lpse_done: >>> + mov sp, x29 >>> + ldp x29, x30, [sp], #176 >>> + ret >>> diff --git a/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/cpp2uno.cxx >>> b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/cpp2uno.cxx >>> new file mode 100644 >>> index 0000000000..6fa6bac7a2 >>> --- /dev/null >>> +++ b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/cpp2uno.cxx >>> @@ -0,0 +1,543 @@ >>> +/************************************************************** >>> + * >>> + * Licensed to the Apache Software Foundation (ASF) under one >>> + * or more contributor license agreements. See the NOTICE file >>> + * distributed with this work for additional information >>> + * regarding copyright ownership. The ASF licenses this file >>> + * to you under the Apache License, Version 2.0 (the >>> + * "License"); you may not use this file except in compliance >>> + * with the License. You may obtain a copy of the License at >>> + * >>> + * http://www.apache.org/licenses/LICENSE-2.0 >>> + * >>> + * Unless required by applicable law or agreed to in writing, >>> + * software distributed under the License is distributed on an >>> + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY >>> + * KIND, either express or implied. See the License for the >>> + * specific language governing permissions and limitations >>> + * under the License. >>> + * >>> + *************************************************************/ >>> + >>> + >>> + >>> +// MARKER(update_precomp.py): autogen include statement, do not remove >>> +#include "precompiled_bridges.hxx" >>> + >>> +#include <stdio.h> >>> +#include <stdlib.h> >>> +#include <hash_map> >>> + >>> +#include <rtl/alloc.h> >>> +#include <osl/mutex.hxx> >>> + >>> +#include <com/sun/star/uno/genfunc.hxx> >>> +#include "com/sun/star/uno/RuntimeException.hpp" >>> +#include <uno/data.h> >>> +#include <typelib/typedescription.hxx> >>> + >>> +#include "bridges/cpp_uno/shared/bridge.hxx" >>> +#include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx" >>> +#include "bridges/cpp_uno/shared/types.hxx" >>> +#include "bridges/cpp_uno/shared/vtablefactory.hxx" >>> + >>> +#include "abi.hxx" >>> +#include "share.hxx" >>> + >>> +using namespace ::osl; >>> +using namespace ::rtl; >>> +using namespace ::com::sun::star::uno; >>> + >>> +//================================================================================================== >>> + >>> +// Perform the UNO call >>> +// >>> +// We must convert the parameters stored in gpreg, fpreg and ovrflw to UNO >>> +// arguments and call pThis->getUnoI()->pDispatcher. >>> +// >>> +// gpreg: this, [gpr params x0..x7] (the indirect-result ptr is x8, >>> separate) >>> +// fpreg: [fpr params d0..d7] >>> +// ovrflw: [gpr or fpr params (properly aligned)] >>> +// >>> +// On AArch64 a structure bigger than 16 bytes is returned via the buffer >>> +// addressed by x8 (pIndirectReturn); 'this' is always x0 = gpreg[0]. >>> +// Simple types are returned in x0,x1 (int) or d0,d1 (fp); HFAs in d0..d3; >>> +// non-HFA structures <= 16 bytes in x0,x1. >>> +static typelib_TypeClass cpp2uno_call( >>> + bridges::cpp_uno::shared::CppInterfaceProxy * pThis, >>> + const typelib_TypeDescription * pMemberTypeDescr, >>> + typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void >>> return >>> + sal_Int32 nParams, typelib_MethodParameter * pParams, >>> + void ** gpreg, void ** fpreg, void ** ovrflw, >>> + void * pIndirectReturn, // AArch64 x8 indirect-result pointer (0 if >>> none) >>> + sal_uInt64 * pRegisterReturn /* space for register return */ ) >>> +{ >>> + unsigned int nr_gpr = 0; //number of gpr registers used >>> + unsigned int nr_fpr = 0; //number of fpr registers used >>> + >>> + // return >>> + typelib_TypeDescription * pReturnTypeDescr = 0; >>> + if (pReturnTypeRef) >>> + TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef ); >>> + >>> + void * pUnoReturn = 0; >>> + void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, >>> reconversion need >>> + >>> + if ( pReturnTypeDescr ) >>> + { >>> + if ( aarch64::return_in_hidden_param( pReturnTypeRef ) ) >>> + { >>> + // AArch64: the indirect-result pointer arrives in x8, >>> NOT in the >>> + // first general-purpose argument register (unlike >>> x86-64 SysV). >>> + // So we take it from pIndirectReturn and do NOT >>> consume a gpreg >>> + // slot here; 'this' still occupies gpreg[0] below. >>> + pCppReturn = pIndirectReturn; >>> + >>> + pUnoReturn = ( >>> bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr ) >>> + ? alloca( >>> pReturnTypeDescr->nSize ) >>> + : pCppReturn ); // direct way >>> + } >>> + else >>> + pUnoReturn = pRegisterReturn; // direct way for simple >>> types >>> + } >>> + >>> + // pop this (x0) >>> + gpreg++; >>> + nr_gpr++; >>> + >>> + // stack space >>> + // parameters >>> + void ** pUnoArgs = reinterpret_cast<void **>(alloca( 4 * sizeof(void *) >>> * nParams )); >>> + void ** pCppArgs = pUnoArgs + nParams; >>> + // indizes of values this have to be converted (interface conversion >>> cpp<=>uno) >>> + sal_Int32 * pTempIndizes = reinterpret_cast<sal_Int32 *>(pUnoArgs + (2 >>> * nParams)); >>> + // type descriptions for reconversions >>> + typelib_TypeDescription ** ppTempParamTypeDescr = >>> reinterpret_cast<typelib_TypeDescription **>(pUnoArgs + (3 * nParams)); >>> + >>> + sal_Int32 nTempIndizes = 0; >>> + >>> + for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) >>> + { >>> + const typelib_MethodParameter & rParam = pParams[nPos]; >>> + >>> + int nUsedGPR = 0; >>> + int nUsedFPR = 0; >>> + bool bFitsRegisters = aarch64::examine_argument( >>> rParam.pTypeRef, false, nUsedGPR, nUsedFPR ); >>> + if ( !rParam.bOut && bridges::cpp_uno::shared::isSimpleType( >>> rParam.pTypeRef ) ) // value >>> + { >>> + // A simple UNO type occupies exactly one register, GPR >>> or FPR. >>> + OSL_ASSERT( bFitsRegisters && ( ( nUsedFPR == 1 && >>> nUsedGPR == 0 ) || ( nUsedFPR == 0 && nUsedGPR == 1 ) ) ); >>> + >>> + if ( nUsedFPR == 1 ) >>> + { >>> + if ( nr_fpr < aarch64::MAX_FPR_REGS ) >>> + { >>> + pCppArgs[nPos] = pUnoArgs[nPos] = >>> fpreg++; >>> + nr_fpr++; >>> + } >>> + else >>> + pCppArgs[nPos] = pUnoArgs[nPos] = >>> ovrflw++; >>> + } >>> + else if ( nUsedGPR == 1 ) >>> + { >>> + if ( nr_gpr < aarch64::MAX_GPR_REGS ) >>> + { >>> + pCppArgs[nPos] = pUnoArgs[nPos] = >>> gpreg++; >>> + nr_gpr++; >>> + } >>> + else >>> + pCppArgs[nPos] = pUnoArgs[nPos] = >>> ovrflw++; >>> + } >>> + } >>> + else // struct <= 16 bytes || ptr to complex value || ref >>> + { >>> + typelib_TypeDescription * pParamTypeDescr = 0; >>> + TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef ); >>> + >>> + void *pCppStack; >>> + if ( nr_gpr < aarch64::MAX_GPR_REGS ) >>> + { >>> + pCppArgs[nPos] = pCppStack = *gpreg++; >>> + nr_gpr++; >>> + } >>> + else >>> + pCppArgs[nPos] = pCppStack = *ovrflw++; >>> + >>> + if (! rParam.bIn) // is pure out >>> + { >>> + // uno out is unconstructed mem! >>> + pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize >>> ); >>> + pTempIndizes[nTempIndizes] = nPos; >>> + // will be released at reconversion >>> + ppTempParamTypeDescr[nTempIndizes++] = >>> pParamTypeDescr; >>> + } >>> + else if ( >>> bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ) ) // is >>> in/inout >>> + { >>> + uno_copyAndConvertData( pUnoArgs[nPos] = >>> alloca( pParamTypeDescr->nSize ), >>> + >>> pCppStack, pParamTypeDescr, >>> + >>> pThis->getBridge()->getCpp2Uno() ); >>> + pTempIndizes[nTempIndizes] = nPos; // has to be >>> reconverted >>> + // will be released at reconversion >>> + ppTempParamTypeDescr[nTempIndizes++] = >>> pParamTypeDescr; >>> + } >>> + else // direct way >>> + { >>> + pUnoArgs[nPos] = pCppStack; >>> + // no longer needed >>> + TYPELIB_DANGER_RELEASE( pParamTypeDescr ); >>> + } >>> + } >>> + } >>> + >>> + // ExceptionHolder >>> + uno_Any aUnoExc; // Any will be constructed by callee >>> + uno_Any * pUnoExc = &aUnoExc; >>> + >>> + // invoke uno dispatch call >>> + (*pThis->getUnoI()->pDispatcher)( pThis->getUnoI(), pMemberTypeDescr, >>> pUnoReturn, pUnoArgs, &pUnoExc ); >>> + >>> + // in case an exception occurred... >>> + if ( pUnoExc ) >>> + { >>> + // destruct temporary in/inout params >>> + for ( ; nTempIndizes--; ) >>> + { >>> + sal_Int32 nIndex = pTempIndizes[nTempIndizes]; >>> + >>> + if (pParams[nIndex].bIn) // is in/inout => was >>> constructed >>> + uno_destructData( pUnoArgs[nIndex], >>> ppTempParamTypeDescr[nTempIndizes], 0 ); >>> + TYPELIB_DANGER_RELEASE( >>> ppTempParamTypeDescr[nTempIndizes] ); >>> + } >>> + if (pReturnTypeDescr) >>> + TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); >>> + >>> + CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc, >>> pThis->getBridge()->getUno2Cpp() ); // has to destruct the any >>> + // is here for dummy >>> + return typelib_TypeClass_VOID; >>> + } >>> + else // else no exception occurred... >>> + { >>> + // temporary params >>> + for ( ; nTempIndizes--; ) >>> + { >>> + sal_Int32 nIndex = pTempIndizes[nTempIndizes]; >>> + typelib_TypeDescription * pParamTypeDescr = >>> ppTempParamTypeDescr[nTempIndizes]; >>> + >>> + if ( pParams[nIndex].bOut ) // inout/out >>> + { >>> + // convert and assign >>> + uno_destructData( pCppArgs[nIndex], >>> pParamTypeDescr, cpp_release ); >>> + uno_copyAndConvertData( pCppArgs[nIndex], >>> pUnoArgs[nIndex], pParamTypeDescr, >>> + >>> pThis->getBridge()->getUno2Cpp() ); >>> + } >>> + // destroy temp uno param >>> + uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 >>> ); >>> + >>> + TYPELIB_DANGER_RELEASE( pParamTypeDescr ); >>> + } >>> + // return >>> + if ( pCppReturn ) // has complex return >>> + { >>> + if ( pUnoReturn != pCppReturn ) // needs reconversion >>> + { >>> + uno_copyAndConvertData( pCppReturn, pUnoReturn, >>> pReturnTypeDescr, >>> + >>> pThis->getBridge()->getUno2Cpp() ); >>> + // destroy temp uno return >>> + uno_destructData( pUnoReturn, pReturnTypeDescr, >>> 0 ); >>> + } >>> + // complex return ptr is set to return reg >>> + *reinterpret_cast<void **>(pRegisterReturn) = >>> pCppReturn; >>> + } >>> + if ( pReturnTypeDescr ) >>> + { >>> + typelib_TypeClass eRet = >>> (typelib_TypeClass)pReturnTypeDescr->eTypeClass; >>> + TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); >>> + return eRet; >>> + } >>> + else >>> + return typelib_TypeClass_VOID; >>> + } >>> +} >>> + >>> + >>> +//================================================================================================== >>> +extern "C" typelib_TypeClass cpp_vtable_call( >>> + sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset, >>> + void ** gpreg, void ** fpreg, void ** ovrflw, >>> + void * pIndirectReturn, // AArch64 x8 indirect-result pointer (0 if >>> none) >>> + sal_uInt64 * pRegisterReturn /* space for register return */ ) >>> +{ >>> + // gpreg: this, [other gpr params x0..x7] >>> + // fpreg: [fpr params d0..d7] >>> + // ovrflw: [gpr or fpr params (properly aligned)] >>> + // pIndirectReturn: x8 (the hidden return buffer), when bit 0x80000000 >>> set. >>> + // >>> + // On AArch64 'this' is ALWAYS x0 = gpreg[0]; the hidden return pointer >>> is >>> + // the separate x8 register, not a displaced first GPR (unlike x86-64 >>> SysV >>> + // where it occupied gpreg[0] and 'this' moved to gpreg[1]). >>> + if ( nFunctionIndex & 0x80000000 ) >>> + nFunctionIndex &= 0x7fffffff; >>> + >>> + void * pThis = gpreg[0]; >>> + pThis = static_cast<char *>( pThis ) - nVtableOffset; >>> + >>> + bridges::cpp_uno::shared::CppInterfaceProxy * pCppI = >>> + >>> bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( pThis ); >>> + >>> + typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr(); >>> + >>> + OSL_ENSURE( nFunctionIndex < >>> pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!\n" ); >>> + if ( nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex ) >>> + { >>> + throw RuntimeException( OUString::createFromAscii("illegal >>> vtable index!"), >>> + >>> reinterpret_cast<XInterface *>( pCppI ) ); >>> + } >>> + >>> + // determine called method >>> + sal_Int32 nMemberPos = >>> pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex]; >>> + OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member >>> index!\n" ); >>> + >>> + TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] ); >>> + >>> + typelib_TypeClass eRet; >>> + switch ( aMemberDescr.get()->eTypeClass ) >>> + { >>> + case typelib_TypeClass_INTERFACE_ATTRIBUTE: >>> + { >>> + typelib_TypeDescriptionReference *pAttrTypeRef = >>> + >>> reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( >>> aMemberDescr.get() )->pAttributeTypeRef; >>> + >>> + if ( >>> pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex ) >>> + { >>> + // is GET method >>> + eRet = cpp2uno_call( pCppI, aMemberDescr.get(), >>> pAttrTypeRef, >>> + 0, 0, // no params >>> + gpreg, fpreg, ovrflw, >>> pIndirectReturn, pRegisterReturn ); >>> + } >>> + else >>> + { >>> + // is SET method >>> + typelib_MethodParameter aParam; >>> + aParam.pTypeRef = pAttrTypeRef; >>> + aParam.bIn = sal_True; >>> + aParam.bOut = sal_False; >>> + >>> + eRet = cpp2uno_call( pCppI, aMemberDescr.get(), >>> + 0, // indicates void return >>> + 1, &aParam, >>> + gpreg, fpreg, ovrflw, >>> pIndirectReturn, pRegisterReturn ); >>> + } >>> + break; >>> + } >>> + case typelib_TypeClass_INTERFACE_METHOD: >>> + { >>> + // is METHOD >>> + switch ( nFunctionIndex ) >>> + { >>> + case 1: // acquire() >>> + pCppI->acquireProxy(); // non virtual >>> call! >>> + eRet = typelib_TypeClass_VOID; >>> + break; >>> + case 2: // release() >>> + pCppI->releaseProxy(); // non virtual >>> call! >>> + eRet = typelib_TypeClass_VOID; >>> + break; >>> + case 0: // queryInterface() opt >>> + { >>> + // queryInterface([in] type) returns an >>> Any (> 16 bytes), >>> + // so on AArch64 the result buffer is >>> x8 (pIndirectReturn), >>> + // 'this' is gpreg[0], and the type >>> argument is the first >>> + // real parameter, gpreg[1]. >>> + typelib_TypeDescription * pTD = 0; >>> + TYPELIB_DANGER_GET( &pTD, >>> reinterpret_cast<Type *>( gpreg[1] )->getTypeLibType() ); >>> + if ( pTD ) >>> + { >>> + XInterface * pInterface = 0; >>> + >>> (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface) >>> + ( >>> pCppI->getBridge()->getCppEnv(), >>> + reinterpret_cast<void >>> **>(&pInterface), >>> + pCppI->getOid().pData, >>> + >>> reinterpret_cast<typelib_InterfaceTypeDescription *>( pTD ) ); >>> + >>> + if ( pInterface ) >>> + { >>> + ::uno_any_construct( >>> reinterpret_cast<uno_Any *>( pIndirectReturn ), >>> + >>> &pInterface, pTD, cpp_acquire ); >>> + >>> + pInterface->release(); >>> + TYPELIB_DANGER_RELEASE( >>> pTD ); >>> + >>> + reinterpret_cast<void >>> **>( pRegisterReturn )[0] = pIndirectReturn; >>> + eRet = >>> typelib_TypeClass_ANY; >>> + break; >>> + } >>> + TYPELIB_DANGER_RELEASE( pTD ); >>> + } >>> + } // else perform queryInterface() >>> + default: >>> + { >>> + typelib_InterfaceMethodTypeDescription >>> *pMethodTD = >>> + >>> reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( >>> aMemberDescr.get() ); >>> + >>> + eRet = cpp2uno_call( pCppI, >>> aMemberDescr.get(), >>> + >>> pMethodTD->pReturnTypeRef, >>> + >>> pMethodTD->nParams, >>> + >>> pMethodTD->pParams, >>> + >>> gpreg, fpreg, ovrflw, pIndirectReturn, pRegisterReturn ); >>> + } >>> + } >>> + break; >>> + } >>> + default: >>> + { >>> + throw RuntimeException( OUString::createFromAscii("no >>> member description found!"), >>> + >>> reinterpret_cast<XInterface *>( pCppI ) ); >>> + // is here for dummy >>> + eRet = typelib_TypeClass_VOID; >>> + } >>> + } >>> + >>> + return eRet; >>> +} >>> + >>> +//================================================================================================== >>> +// The incoming register-spill executor, implemented in call.s. It is >>> reached >>> +// via BR from a per-slot snippet (codeSnippet below) with x16 carrying the >>> +// packed (nVtableOffset << 32) | nFunctionIndex; it spills the argument >>> +// registers and calls cpp_vtable_call. >>> +extern "C" void privateSnippetExecutor( void ); >>> + >>> +// Each snippet is 5 AArch64 instructions (20 bytes) + 4 bytes padding to >>> an >>> +// 8-byte boundary + two 8-byte literals (the packed index and the executor >>> +// address) = 40 bytes. >>> +const int codeSnippetSize = 40; >>> + >>> +// Generate a per-vtable-slot trampoline that loads the packed function >>> index >>> +// into x16 and branches to privateSnippetExecutor(), preserving every >>> +// argument register. Uses PC-relative literal loads because AArch64 >>> cannot >>> +// embed a 64-bit immediate in a single instruction. >>> +// >>> +// Layout (offsets in bytes from code): >>> +// 0: ldr x16, #24 ; x16 = nOffsetAndIndex (literal at +24) >>> +// 4: ldr x17, #28 ; x17 = privateSnippetExecutor (literal at >>> +32) >>> +// 8: br x17 >>> +// 12: (unused / padding) >>> +// 16: (padding to 8-byte align the literals at 24) >>> +// 24: .quad nOffsetAndIndex >>> +// 32: .quad privateSnippetExecutor >>> +// >>> +// Note: the snippet creates no stack frame, so the C++ unwinder walks >>> straight >>> +// through it to the original caller (required for UNO exception >>> propagation). >>> +unsigned char * codeSnippet( unsigned char * code, >>> + sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset, >>> + bool bHasHiddenParam ) SAL_THROW( () ) >>> +{ >>> + sal_uInt64 nOffsetAndIndex = ( static_cast<sal_uInt64>( nVtableOffset ) >>> << 32 ) | static_cast<sal_uInt64>( nFunctionIndex ); >>> + >>> + if ( bHasHiddenParam ) >>> + nOffsetAndIndex |= 0x80000000; >>> + >>> + sal_uInt32 * p = reinterpret_cast<sal_uInt32 *>( code ); >>> + >>> + // ldr x16, #24 -> literal at code+24. imm19 = 24/4 = 6. >>> + // encoding: 0x58000000 | (imm19 << 5) | Rt(16) >>> + p[0] = 0x58000000 | ( 6 << 5 ) | 16; >>> + // ldr x17, #28 -> literal at code+32 (relative to this insn at +4): >>> 28. >>> + // imm19 = 28/4 = 7. >>> + p[1] = 0x58000000 | ( 7 << 5 ) | 17; >>> + // br x17 -> 0xD61F0000 | (Rn(17) << 5) >>> + p[2] = 0xD61F0000 | ( 17 << 5 ); >>> + // p[3] (offset 12) and p[4] (offset 16..20) are padding. >>> + p[3] = 0xD503201F; // NOP >>> + p[4] = 0xD503201F; // NOP >>> + >>> + // literals, 8-byte aligned at offset 24 and 32 >>> + *reinterpret_cast<sal_uInt64 *>( code + 24 ) = nOffsetAndIndex; >>> + *reinterpret_cast<sal_uInt64 *>( code + 32 ) = >>> reinterpret_cast<sal_uInt64>( privateSnippetExecutor ); >>> + >>> + return code + codeSnippetSize; >>> +} >>> + >>> +//================================================================================================== >>> +struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; >>> + >>> +bridges::cpp_uno::shared::VtableFactory::Slot * >>> +bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) >>> +{ >>> + return static_cast< Slot * >(block) + 2; >>> +} >>> + >>> +//================================================================================================== >>> +sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize( >>> + sal_Int32 slotCount) >>> +{ >>> + return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize; >>> +} >>> + >>> +//================================================================================================== >>> +bridges::cpp_uno::shared::VtableFactory::Slot * >>> +bridges::cpp_uno::shared::VtableFactory::initializeBlock( >>> + void * block, sal_Int32 slotCount) >>> +{ >>> + Slot * slots = mapBlockToVtable(block); >>> + slots[-2].fn = 0; >>> + slots[-1].fn = 0; >>> + return slots + slotCount; >>> +} >>> + >>> +//================================================================================================== >>> + >>> +unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions( >>> + Slot ** slots, unsigned char * code, /*sal_PtrDiff writetoexecdiff,*/ >>> + typelib_InterfaceTypeDescription const * type, sal_Int32 >>> nFunctionOffset, >>> + sal_Int32 functionCount, sal_Int32 nVtableOffset ) >>> +{ >>> + const sal_PtrDiff writetoexecdiff = 0; >>> + (*slots) -= functionCount; >>> + Slot * s = *slots; >>> + for ( sal_Int32 nPos = 0; nPos < type->nMembers; ++nPos ) >>> + { >>> + typelib_TypeDescription * pTD = 0; >>> + >>> + TYPELIB_DANGER_GET( &pTD, type->ppMembers[ nPos ] ); >>> + OSL_ASSERT( pTD ); >>> + >>> + if ( typelib_TypeClass_INTERFACE_ATTRIBUTE == pTD->eTypeClass ) >>> + { >>> + typelib_InterfaceAttributeTypeDescription *pAttrTD = >>> + >>> reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( pTD ); >>> + >>> + // get method >>> + (s++)->fn = code + writetoexecdiff; >>> + code = codeSnippet( code, nFunctionOffset++, >>> nVtableOffset, >>> + >>> aarch64::return_in_hidden_param( pAttrTD->pAttributeTypeRef ) ); >>> + >>> + if ( ! pAttrTD->bReadOnly ) >>> + { >>> + // set method >>> + (s++)->fn = code + writetoexecdiff; >>> + code = codeSnippet( code, nFunctionOffset++, >>> nVtableOffset, false ); >>> + } >>> + } >>> + else if ( typelib_TypeClass_INTERFACE_METHOD == pTD->eTypeClass >>> ) >>> + { >>> + typelib_InterfaceMethodTypeDescription *pMethodTD = >>> + >>> reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( pTD ); >>> + >>> + (s++)->fn = code + writetoexecdiff; >>> + code = codeSnippet( code, nFunctionOffset++, >>> nVtableOffset, >>> + >>> aarch64::return_in_hidden_param( pMethodTD->pReturnTypeRef ) ); >>> + } >>> + else >>> + OSL_ASSERT( false ); >>> + >>> + TYPELIB_DANGER_RELEASE( pTD ); >>> + } >>> + return code; >>> +} >>> + >>> +//================================================================================================== >>> +void bridges::cpp_uno::shared::VtableFactory::flushCode( >>> + unsigned char const *, unsigned char const * ) >>> +{ >>> +} >>> diff --git a/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/except.cxx >>> b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/except.cxx >>> new file mode 100644 >>> index 0000000000..60784a4172 >>> --- /dev/null >>> +++ b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/except.cxx >>> @@ -0,0 +1,358 @@ >>> +/************************************************************** >>> + * >>> + * Licensed to the Apache Software Foundation (ASF) under one >>> + * or more contributor license agreements. See the NOTICE file >>> + * distributed with this work for additional information >>> + * regarding copyright ownership. The ASF licenses this file >>> + * to you under the Apache License, Version 2.0 (the >>> + * "License"); you may not use this file except in compliance >>> + * with the License. You may obtain a copy of the License at >>> + * >>> + * http://www.apache.org/licenses/LICENSE-2.0 >>> + * >>> + * Unless required by applicable law or agreed to in writing, >>> + * software distributed under the License is distributed on an >>> + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY >>> + * KIND, either express or implied. See the License for the >>> + * specific language governing permissions and limitations >>> + * under the License. >>> + * >>> + *************************************************************/ >>> + >>> + >>> + >>> +// MARKER(update_precomp.py): autogen include statement, do not remove >>> +#include "precompiled_bridges.hxx" >>> + >>> +#if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) >>> +#include <exception> >>> +#endif >>> + >>> +#include <stdio.h> >>> +#include <string.h> >>> +#include <dlfcn.h> >>> +#include <cxxabi.h> >>> +#include <hash_map> >>> +#include <sys/param.h> >>> + >>> +#include <rtl/strbuf.hxx> >>> +#include <rtl/ustrbuf.hxx> >>> +#include <osl/diagnose.h> >>> +#include <osl/mutex.hxx> >>> + >>> +#include <com/sun/star/uno/genfunc.hxx> >>> +#include "com/sun/star/uno/RuntimeException.hpp" >>> +#include <typelib/typedescription.hxx> >>> +#include <uno/any2.h> >>> + >>> +#include "share.hxx" >>> + >>> + >>> +using namespace ::std; >>> +using namespace ::osl; >>> +using namespace ::rtl; >>> +using namespace ::com::sun::star::uno; >>> +using namespace ::__cxxabiv1; >>> + >>> + >>> +namespace CPPU_CURRENT_NAMESPACE >>> +{ >>> + >>> +void dummy_can_throw_anything( char const * ) >>> +{ >>> +} >>> + >>> +//================================================================================================== >>> +static OUString toUNOname( char const * p ) SAL_THROW( () ) >>> +{ >>> +#if OSL_DEBUG_LEVEL > 1 >>> + char const * start = p; >>> +#endif >>> + >>> + // example: N3com3sun4star4lang24IllegalArgumentExceptionE >>> + >>> + OUStringBuffer buf( 64 ); >>> + OSL_ASSERT( 'N' == *p ); >>> + ++p; // skip N >>> + >>> + while ('E' != *p) >>> + { >>> + // read chars count >>> + long n = (*p++ - '0'); >>> + while ('0' <= *p && '9' >= *p) >>> + { >>> + n *= 10; >>> + n += (*p++ - '0'); >>> + } >>> + buf.appendAscii( p, n ); >>> + p += n; >>> + if ('E' != *p) >>> + buf.append( (sal_Unicode)'.' ); >>> + } >>> + >>> +#if OSL_DEBUG_LEVEL > 1 >>> + OUString ret( buf.makeStringAndClear() ); >>> + OString c_ret( OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ) ); >>> + fprintf( stderr, "> toUNOname(): %s => %s\n", start, c_ret.getStr() ); >>> + return ret; >>> +#else >>> + return buf.makeStringAndClear(); >>> +#endif >>> +} >>> + >>> +//================================================================================================== >>> +class RTTI >>> +{ >>> + typedef hash_map< OUString, type_info *, OUStringHash > t_rtti_map; >>> + >>> + Mutex m_mutex; >>> + t_rtti_map m_rttis; >>> + t_rtti_map m_generatedRttis; >>> + >>> + void * m_hApp; >>> + >>> +public: >>> + RTTI() SAL_THROW( () ); >>> + ~RTTI() SAL_THROW( () ); >>> + >>> + type_info * getRTTI( typelib_CompoundTypeDescription * ) SAL_THROW( () >>> ); >>> +}; >>> + >>> +//__________________________________________________________________________________________________ >>> +RTTI::RTTI() SAL_THROW( () ) >>> + : m_hApp( dlopen( 0, RTLD_LAZY ) ) >>> +{ >>> +} >>> + >>> +//__________________________________________________________________________________________________ >>> +RTTI::~RTTI() SAL_THROW( () ) >>> +{ >>> + dlclose( m_hApp ); >>> +} >>> + >>> +//__________________________________________________________________________________________________ >>> +type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr ) >>> SAL_THROW( () ) >>> +{ >>> + type_info * rtti; >>> + >>> + OUString const & unoName = *(OUString const >>> *)&pTypeDescr->aBase.pTypeName; >>> + >>> + MutexGuard guard( m_mutex ); >>> + t_rtti_map::const_iterator iFind( m_rttis.find( unoName ) ); >>> + if (iFind == m_rttis.end()) >>> + { >>> + // RTTI symbol >>> + OStringBuffer buf( 64 ); >>> + buf.append( RTL_CONSTASCII_STRINGPARAM("_ZTIN") ); >>> + sal_Int32 index = 0; >>> + do >>> + { >>> + OUString token( unoName.getToken( 0, '.', index ) ); >>> + buf.append( token.getLength() ); >>> + OString c_token( OUStringToOString( token, >>> RTL_TEXTENCODING_ASCII_US ) ); >>> + buf.append( c_token ); >>> + } >>> + while (index >= 0); >>> + buf.append( 'E' ); >>> + >>> + OString symName( buf.makeStringAndClear() ); >>> + rtti = static_cast<std::type_info *>(dlsym( m_hApp, >>> symName.getStr() )); >>> + >>> + if (rtti) >>> + { >>> + pair< t_rtti_map::iterator, bool > insertion( >>> + m_rttis.insert( t_rtti_map::value_type( unoName, rtti ) ) >>> ); >>> + OSL_ENSURE( insertion.second, "### inserting new rtti >>> failed?!" ); >>> + } >>> + else >>> + { >>> + // try to lookup the symbol in the generated rtti map >>> + t_rtti_map::const_iterator iFind2( m_generatedRttis.find( >>> unoName ) ); >>> + if (iFind2 == m_generatedRttis.end()) >>> + { >>> + // we must generate it ! >>> + // symbol and rtti-name is nearly identical, >>> + // the symbol is prefixed with _ZTI >>> + char const * rttiName = symName.getStr() +4; >>> +#if OSL_DEBUG_LEVEL > 1 >>> + fprintf( stderr,"generated rtti for %s\n", rttiName ); >>> + const OString aCUnoName = OUStringToOString( unoName, >>> RTL_TEXTENCODING_UTF8); >>> + OSL_TRACE( "TypeInfo for \"%s\" not found and cannot be >>> generated.\n", aCUnoName.getStr()); >>> +#endif >>> +#ifndef AOO_BYPASS_RTTI >>> + if (pTypeDescr->pBaseTypeDescription) >>> + { >>> + // ensure availability of base >>> + type_info * base_rtti = getRTTI( >>> + (typelib_CompoundTypeDescription >>> *)pTypeDescr->pBaseTypeDescription ); >>> + rtti = new __si_class_type_info( >>> + strdup( rttiName ), (__class_type_info *)base_rtti >>> ); >>> + } >>> + else >>> + { >>> + // this class has no base class >>> + rtti = new __class_type_info( strdup( rttiName ) ); >>> + } >>> +#else >>> + rtti = NULL; >>> +#endif >>> + bool bOK = m_generatedRttis.insert( >>> t_rtti_map::value_type( unoName, rtti )).second; >>> + OSL_ENSURE( bOK, "### inserting new generated rtti >>> failed?!" ); >>> + } >>> + else // taking already generated rtti >>> + { >>> + rtti = iFind2->second; >>> + } >>> + } >>> + } >>> + else >>> + { >>> + rtti = iFind->second; >>> + } >>> + >>> + return rtti; >>> +} >>> + >>> +//-------------------------------------------------------------------------------------------------- >>> +static void deleteException( void * pExc ) >>> +{ >>> + __cxa_exception const * header = static_cast<__cxa_exception const >>> *>(pExc) - 1; >>> + /* More __cxa_exception mumbo-jumbo. See share.hxx and >>> fillUnoException() below */ >>> + if (header->exceptionDestructor != &deleteException) >>> + { >>> + header = reinterpret_cast<__cxa_exception const >>> *>(reinterpret_cast<char const *>(header) - 8); >>> + } >>> + if( !header->exceptionType) >>> + { >>> + return; // NOTE: leak for now >>> + } >>> + typelib_TypeDescription * pTD = 0; >>> + OUString unoName( toUNOname( header->exceptionType->name() ) ); >>> + ::typelib_typedescription_getByName( &pTD, unoName.pData ); >>> + OSL_ENSURE( pTD, "### unknown exception type! leaving out destruction >>> => leaking!!!" ); >>> + if (pTD) >>> + { >>> + ::uno_destructData( pExc, pTD, cpp_release ); >>> + ::typelib_typedescription_release( pTD ); >>> + } >>> +} >>> + >>> +//================================================================================================== >>> +void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp ) >>> +{ >>> +#if OSL_DEBUG_LEVEL > 1 >>> + OString cstr( >>> + OUStringToOString( >>> + *reinterpret_cast< OUString const * >( >>> &pUnoExc->pType->pTypeName ), >>> + RTL_TEXTENCODING_ASCII_US ) ); >>> + fprintf( stderr, "> uno exception occurred: %s\n", cstr.getStr() ); >>> +#endif >>> + void * pCppExc; >>> + type_info * rtti; >>> + >>> + { >>> + // construct cpp exception object >>> + typelib_TypeDescription * pTypeDescr = 0; >>> + TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType ); >>> + OSL_ASSERT( pTypeDescr ); >>> + if (! pTypeDescr) >>> + { >>> + throw RuntimeException( >>> + OUString( RTL_CONSTASCII_USTRINGPARAM("cannot get >>> typedescription for type ") ) + >>> + *reinterpret_cast< OUString const * >( >>> &pUnoExc->pType->pTypeName ), >>> + Reference< XInterface >() ); >>> + } >>> + >>> + pCppExc = __cxa_allocate_exception( pTypeDescr->nSize ); >>> + ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp >>> ); >>> + >>> + // destruct uno exception >>> + ::uno_any_destruct( pUnoExc, 0 ); >>> + // avoiding locked counts >>> + static RTTI * s_rtti = 0; >>> + if (! s_rtti) >>> + { >>> + MutexGuard guard( Mutex::getGlobalMutex() ); >>> + if (! s_rtti) >>> + { >>> +#ifdef LEAK_STATIC_DATA >>> + s_rtti = new RTTI(); >>> +#else >>> + static RTTI rtti_data; >>> + s_rtti = &rtti_data; >>> +#endif >>> + } >>> + } >>> + rtti = (type_info *)s_rtti->getRTTI( (typelib_CompoundTypeDescription >>> *) pTypeDescr ); >>> + TYPELIB_DANGER_RELEASE( pTypeDescr ); >>> + OSL_ENSURE( rtti, "### no rtti for throwing exception!" ); >>> + if (! rtti) >>> + { >>> + throw RuntimeException( >>> + OUString( RTL_CONSTASCII_USTRINGPARAM("no rtti for type ") ) + >>> + *reinterpret_cast< OUString const * >( >>> &pUnoExc->pType->pTypeName ), >>> + Reference< XInterface >() ); >>> + } >>> + } >>> + >>> + __cxa_throw( pCppExc, rtti, deleteException ); >>> +} >>> + >>> +//================================================================================================== >>> +void fillUnoException( __cxa_exception * header, uno_Any * pUnoExc, >>> uno_Mapping * pCpp2Uno ) >>> +{ >>> + if (! header) >>> + { >>> + RuntimeException aRE( >>> + OUString( RTL_CONSTASCII_USTRINGPARAM("no exception header!") >>> ), >>> + Reference< XInterface >() ); >>> + Type const & rType = ::getCppuType( &aRE ); >>> + uno_type_any_constructAndConvert( pUnoExc, &aRE, >>> rType.getTypeLibType(), pCpp2Uno ); >>> +#if OSL_DEBUG_LEVEL > 0 >>> + OString cstr( OUStringToOString( aRE.Message, >>> RTL_TEXTENCODING_ASCII_US ) ); >>> + OSL_ENSURE( 0, cstr.getStr() ); >>> +#endif >>> + return; >>> + } >>> + >>> + /* >>> + * Handle the case where we are built on llvm 10 (or later) but are >>> running >>> + * on an earlier version (eg, community builds). In this situation the >>> + * reserved ptr doesn't exist in the struct returned and so the offsets >>> + * that header uses are wrong. This assumes that reserved isn't used >>> + * and that referenceCount is always >0 in the cases we handle. >>> + * See share.hxx for the definition of __cxa_exception >>> + */ >>> + if (*reinterpret_cast<void **>(header) == 0) >>> + { >>> + header = reinterpret_cast<__cxa_exception *>(reinterpret_cast<char >>> *>(header) + 8); >>> + } >>> + >>> + typelib_TypeDescription * pExcTypeDescr = 0; >>> + OUString unoName( toUNOname( header->exceptionType->name() ) ); >>> +#if OSL_DEBUG_LEVEL > 1 >>> + OString cstr_unoName( OUStringToOString( unoName, >>> RTL_TEXTENCODING_ASCII_US ) ); >>> + fprintf( stderr, "> c++ exception occurred: %s\n", >>> cstr_unoName.getStr() ); >>> +#endif >>> + typelib_typedescription_getByName( &pExcTypeDescr, unoName.pData ); >>> + if (0 == pExcTypeDescr) >>> + { >>> + RuntimeException aRE( >>> + OUString( RTL_CONSTASCII_USTRINGPARAM("exception type not >>> found: ") ) + unoName, >>> + Reference< XInterface >() ); >>> + Type const & rType = ::getCppuType( &aRE ); >>> + uno_type_any_constructAndConvert( pUnoExc, &aRE, >>> rType.getTypeLibType(), pCpp2Uno ); >>> +#if OSL_DEBUG_LEVEL > 0 >>> + OString cstr( OUStringToOString( aRE.Message, >>> RTL_TEXTENCODING_ASCII_US ) ); >>> + OSL_ENSURE( 0, cstr.getStr() ); >>> +#endif >>> + } >>> + else >>> + { >>> + // construct uno exception any >>> + uno_any_constructAndConvert( pUnoExc, header->adjustedPtr, >>> pExcTypeDescr, pCpp2Uno ); >>> + typelib_typedescription_release( pExcTypeDescr ); >>> + } >>> +} >>> + >>> +} >>> diff --git a/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/makefile.mk >>> b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/makefile.mk >>> new file mode 100644 >>> index 0000000000..af6c6c22d4 >>> --- /dev/null >>> +++ b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/makefile.mk >>> @@ -0,0 +1,81 @@ >>> +#************************************************************** >>> +# >>> +# Licensed to the Apache Software Foundation (ASF) under one >>> +# or more contributor license agreements. See the NOTICE file >>> +# distributed with this work for additional information >>> +# regarding copyright ownership. The ASF licenses this file >>> +# to you under the Apache License, Version 2.0 (the >>> +# "License"); you may not use this file except in compliance >>> +# with the License. You may obtain a copy of the License at >>> +# >>> +# http://www.apache.org/licenses/LICENSE-2.0 >>> +# >>> +# Unless required by applicable law or agreed to in writing, >>> +# software distributed under the License is distributed on an >>> +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY >>> +# KIND, either express or implied. See the License for the >>> +# specific language governing permissions and limitations >>> +# under the License. >>> +# >>> +#************************************************************** >>> + >>> + >>> + >>> +PRJ=..$/..$/.. >>> + >>> +PRJNAME=bridges >>> +TARGET=$(COMNAME)_uno >>> +LIBTARGET=no >>> +ENABLE_EXCEPTIONS=TRUE >>> + >>> +# --- Settings ----------------------------------------------------- >>> + >>> +.INCLUDE : settings.mk >>> + >>> +# --- Files -------------------------------------------------------- >>> + >>> +# Apple Silicon (arm64 / AAPCS64) C++-UNO bridge. CPU=R, CPUNAME=AARCH64. >>> +# Note: the "s5abi" in this directory's name is the macOS-wide COMNAME (see >>> +# solenv/gbuild/platform/macosx.mk); the actual arm64 calling convention is >>> +# AAPCS64, so "s5abi" here is a historical label, not a literal ABI claim. >>> +.IF "$(OS)$(CPU)" == "MACOSXR" >>> + >>> +.IF "$(cppu_no_leak)" == "" >>> +CFLAGS += -DLEAK_STATIC_DATA >>> +.ENDIF >>> + >>> +# In case someone enabled the non-standard -fomit-frame-pointer which does >>> not >>> +# work with the .cxx sources in this directory: >>> +CFLAGSCXX += -fno-omit-frame-pointer -fnon-call-exceptions >>> + >>> +SLOFILES= \ >>> + $(SLO)$/abi.obj \ >>> + $(SLO)$/except.obj \ >>> + $(SLO)$/cpp2uno.obj \ >>> + $(SLO)$/uno2cpp.obj \ >>> + $(SLO)$/call.obj >>> + >>> +SHL1TARGET= $(TARGET) >>> + >>> +SHL1DEF=$(MISC)$/$(SHL1TARGET).def >>> +SHL1IMPLIB=i$(TARGET) >>> +SHL1VERSIONMAP=..$/..$/bridge_exports.map >>> +SHL1RPATH=URELIB >>> + >>> +SHL1OBJS = $(SLOFILES) >>> +SHL1LIBS = $(SLB)$/cpp_uno_shared.lib >>> + >>> +SHL1STDLIBS= \ >>> + $(CPPULIB) \ >>> + $(SALLIB) >>> + >>> +.ENDIF >>> + >>> +# --- Targets ------------------------------------------------------ >>> + >>> +.INCLUDE : target.mk >>> + >>> +# Assemble the AArch64 call trampoline (call.s) into call.obj, mirroring >>> the >>> +# pattern rule used by the gcc3_linux_arm bridge for its armhelper.S. >>> +$(SLO)$/%.obj: %.s >>> + $(CXX) -c -o $(SLO)$/$(@:b).o $< -fPIC ; touch $@ >>> diff --git a/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/share.hxx >>> b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/share.hxx >>> new file mode 100644 >>> index 0000000000..e4fcf4dbf9 >>> --- /dev/null >>> +++ b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/share.hxx >>> @@ -0,0 +1,116 @@ >>> +/************************************************************** >>> + * >>> + * Licensed to the Apache Software Foundation (ASF) under one >>> + * or more contributor license agreements. See the NOTICE file >>> + * distributed with this work for additional information >>> + * regarding copyright ownership. The ASF licenses this file >>> + * to you under the Apache License, Version 2.0 (the >>> + * "License"); you may not use this file except in compliance >>> + * with the License. You may obtain a copy of the License at >>> + * >>> + * http://www.apache.org/licenses/LICENSE-2.0 >>> + * >>> + * Unless required by applicable law or agreed to in writing, >>> + * software distributed under the License is distributed on an >>> + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY >>> + * KIND, either express or implied. See the License for the >>> + * specific language governing permissions and limitations >>> + * under the License. >>> + * >>> + *************************************************************/ >>> + >>> + >>> + >>> +#include "uno/mapping.h" >>> + >>> +#include <typeinfo> >>> +#include <exception> >>> +#include <cstddef> >>> + >>> +namespace CPPU_CURRENT_NAMESPACE >>> +{ >>> + >>> +void dummy_can_throw_anything( char const * ); >>> + >>> +typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__))); >>> + >>> +// ----- the following structure is compatible with the one declared in >>> libunwind's unwind.h >>> +// (use forced types) >>> + >>> +struct _Unwind_Exception >>> +{ >>> + uint64_t exception_class; >>> + void * exception_cleanup; >>> + uintptr_t private_1; >>> + uintptr_t private_2; >>> +}; >>> + >>> +struct __cxa_exception >>> +{ >>> + /* From LLVM 10 a reserved member was added at the top of the struct on >>> + 64-bit targets. Who the hell does that? >>> + https://reviews.llvm.org/rG674ec1eb16678b8addc02a4b0534ab383d22fa77 >>> + It is required on arm64 (Apple Silicon): the trailing >>> _Unwind_Exception >>> + must be 16-byte aligned within the allocation, and only WITH this >>> member >>> + does unwindHeader land at a 16-byte boundary (offset 96, vs a >>> misaligned >>> + 88 without it). Verified empirically against this host's libc++abi. >>> + NOTE: Apple clang version != upstream LLVM version. */ >>> + void *reserved; >>> + size_t referenceCount; >>> + ::std::type_info *exceptionType; >>> + void (*exceptionDestructor)(void *); >>> + ::std::unexpected_handler unexpectedHandler; >>> + ::std::terminate_handler terminateHandler; >>> + __cxa_exception *nextException; >>> + int handlerCount; >>> + int handlerSwitchValue; >>> + const unsigned char *actionRecord; >>> + const unsigned char *languageSpecificData; >>> + void *catchTemp; >>> + void *adjustedPtr; >>> + _Unwind_Exception unwindHeader; >>> +}; >>> + >>> +extern "C" void *__cxa_allocate_exception( >>> + std::size_t thrown_size ) throw(); >>> +extern "C" void __cxa_throw ( >>> + void *thrown_exception, std::type_info *tinfo, void (*dest) (void *) ) >>> __attribute__((noreturn)); >>> + >>> +struct __cxa_eh_globals >>> +{ >>> + __cxa_exception *caughtExceptions; >>> + unsigned int uncaughtExceptions; >>> +}; >>> +extern "C" __cxa_eh_globals *__cxa_get_globals () throw(); >>> + >>> +// ----- >>> + >>> +// on OSX 64bit the class_type_info classes are specified >>> +// in http://refspecs.linuxbase.org/cxxabi-1.86.html#rtti but >>> +// these details are not generally available in a public header >>> +// of most development environments. So we define them here. >>> +// NOTE: >>> https://www.hexblog.com/wp-content/uploads/2012/06/Recon-2012-Skochinsky-Compiler-Internals.pdf >>> +class __class_type_info : public std::type_info >>> +{ >>> +public: >>> + explicit __class_type_info( const char* pRttiName) >>> + : std::type_info( pRttiName) >>> + {} >>> +}; >>> + >>> +class __si_class_type_info : public __class_type_info >>> +{ >>> + const __class_type_info* mpBaseType; >>> +public: >>> + explicit __si_class_type_info( const char* pRttiName, >>> __class_type_info* pBaseType) >>> + : __class_type_info( pRttiName), mpBaseType( pBaseType) >>> + {} >>> +}; >>> + >>> +//================================================================================================== >>> +void raiseException( >>> + uno_Any * pUnoExc, uno_Mapping * pUno2Cpp ); >>> +//================================================================================================== >>> +void fillUnoException( >>> + __cxa_exception * header, uno_Any *, uno_Mapping * pCpp2Uno ); >>> +} >>> diff --git a/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/uno2cpp.cxx >>> b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/uno2cpp.cxx >>> new file mode 100644 >>> index 0000000000..adaa3f2a5f >>> --- /dev/null >>> +++ b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/uno2cpp.cxx >>> @@ -0,0 +1,581 @@ >>> +/************************************************************** >>> + * >>> + * Licensed to the Apache Software Foundation (ASF) under one >>> + * or more contributor license agreements. See the NOTICE file >>> + * distributed with this work for additional information >>> + * regarding copyright ownership. The ASF licenses this file >>> + * to you under the Apache License, Version 2.0 (the >>> + * "License"); you may not use this file except in compliance >>> + * with the License. You may obtain a copy of the License at >>> + * >>> + * http://www.apache.org/licenses/LICENSE-2.0 >>> + * >>> + * Unless required by applicable law or agreed to in writing, >>> + * software distributed under the License is distributed on an >>> + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY >>> + * KIND, either express or implied. See the License for the >>> + * specific language governing permissions and limitations >>> + * under the License. >>> + * >>> + *************************************************************/ >>> + >>> + >>> + >>> +// MARKER(update_precomp.py): autogen include statement, do not remove >>> +#include "precompiled_bridges.hxx" >>> + >>> +#include <exception> >>> +#include <typeinfo> >>> +#include <stdio.h> >>> +#include <stdlib.h> >>> +#include <string.h> >>> + >>> +#include "rtl/alloc.h" >>> +#include "rtl/ustrbuf.hxx" >>> + >>> +#include <com/sun/star/uno/genfunc.hxx> >>> +#include "com/sun/star/uno/RuntimeException.hpp" >>> +#include <uno/data.h> >>> + >>> +#include <bridges/cpp_uno/shared/bridge.hxx> >>> +#include <bridges/cpp_uno/shared/types.hxx> >>> +#include "bridges/cpp_uno/shared/unointerfaceproxy.hxx" >>> +#include "bridges/cpp_uno/shared/vtables.hxx" >>> + >>> +#include "abi.hxx" >>> +#include "share.hxx" >>> + >>> +using namespace ::rtl; >>> +using namespace ::com::sun::star::uno; >>> + >>> +//================================================================================================== >>> + >>> +// The AArch64 outgoing-call trampoline, implemented in call.s. It loads >>> the >>> +// argument registers from the caller-prepared arrays, copies overflow >>> args to >>> +// the outgoing stack, performs the indirect call, and returns x0/x1 and >>> d0..d3. >>> +extern "C" void callVirtualFunction( >>> + sal_uInt64 pFunction, sal_uInt64 pIndirectRet, >>> + sal_uInt64 *pGPR, double *pFPR, >>> + sal_uInt64 *pStack, sal_uInt32 nStackWords, >>> + sal_uInt64 *pGPRReturn, double *pFPRReturn ); >>> + >>> +static void callVirtualMethod(void * pThis, sal_uInt32 nVtableIndex, >>> + void * pRegisterReturn, >>> typelib_TypeDescriptionReference * pReturnTypeRef, bool bSimpleReturn, >>> + void * pIndirectReturn, >>> + sal_uInt64 *pStack, sal_uInt32 nStack, >>> + sal_uInt64 *pGPR, sal_uInt32 nGPR, >>> + double *pFPR, sal_uInt32 nFPR) >>> __attribute__((noinline)); >>> + >>> +static void callVirtualMethod(void * pThis, sal_uInt32 nVtableIndex, >>> + void * pRegisterReturn, >>> typelib_TypeDescriptionReference * pReturnTypeRef, bool bSimpleReturn, >>> + void * pIndirectReturn, >>> + sal_uInt64 *pStack, sal_uInt32 nStack, >>> + sal_uInt64 *pGPR, sal_uInt32 nGPR, >>> + double *pFPR, sal_uInt32 nFPR) >>> +{ >>> +#if OSL_DEBUG_LEVEL > 1 >>> + // Let's figure out what is really going on here >>> + { >>> + fprintf( stderr, "= callVirtualMethod() =\nGPR's (%d): ", nGPR ); >>> + for ( unsigned int i = 0; i < nGPR; ++i ) >>> + fprintf( stderr, "0x%lx, ", pGPR[i] ); >>> + fprintf( stderr, "\nFPR's (%d): ", nFPR ); >>> + for ( unsigned int i = 0; i < nFPR; ++i ) >>> + fprintf( stderr, "%f, ", pFPR[i] ); >>> + fprintf( stderr, "\nStack (%d): ", nStack ); >>> + for ( unsigned int i = 0; i < nStack; ++i ) >>> + fprintf( stderr, "0x%lx, ", pStack[i] ); >>> + fprintf( stderr, "\n" ); >>> + } >>> +#endif >>> + >>> + // The call instruction within callVirtualFunction may throw >>> exceptions. So >>> + // that the compiler handles this correctly, it is important that (a) >>> + // callVirtualMethod might call dummy_can_throw_anything (although >>> this never >>> + // happens at runtime), which in turn can throw exceptions, and (b) >>> + // callVirtualMethod is not inlined at its call site (so that any >>> exceptions >>> + // thrown across the call are caught): >>> + if ( !pThis ) >>> + CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything( "xxx" ); // >>> address something >>> + >>> + // Should not happen, but... >>> + if ( nFPR > aarch64::MAX_FPR_REGS ) >>> + nFPR = aarch64::MAX_FPR_REGS; >>> + if ( nGPR > aarch64::MAX_GPR_REGS ) >>> + nGPR = aarch64::MAX_GPR_REGS; >>> + >>> + // Get pointer to the C++ virtual method from the vtable. >>> + sal_uInt64 pMethod = *((sal_uInt64 *)pThis); >>> + pMethod += 8 * nVtableIndex; >>> + pMethod = *((sal_uInt64 *)pMethod); >>> + >>> + // Return register save areas: x0,x1 and d0..d3 (HFA up to 4 elements). >>> + sal_uInt64 gpReturn[2] = { 0, 0 }; >>> + double fpReturn[4] = { 0, 0, 0, 0 }; >>> + >>> + // Ensure the GPR/FPR arrays are the full register width even if fewer >>> were >>> + // filled (the trampoline always loads all 8 of each). >>> + sal_uInt64 gpr[aarch64::MAX_GPR_REGS]; >>> + double fpr[aarch64::MAX_FPR_REGS]; >>> + for ( sal_uInt32 i = 0; i < aarch64::MAX_GPR_REGS; ++i ) >>> + gpr[i] = ( i < nGPR ) ? pGPR[i] : 0; >>> + for ( sal_uInt32 i = 0; i < aarch64::MAX_FPR_REGS; ++i ) >>> + fpr[i] = ( i < nFPR ) ? pFPR[i] : 0; >>> + >>> + callVirtualFunction( >>> + pMethod, >>> + reinterpret_cast<sal_uInt64>( pIndirectReturn ), // x8, 0 if none >>> + gpr, fpr, >>> + pStack, nStack, >>> + gpReturn, fpReturn ); >>> + >>> + switch (pReturnTypeRef->eTypeClass) >>> + { >>> + case typelib_TypeClass_HYPER: >>> + case typelib_TypeClass_UNSIGNED_HYPER: >>> + *reinterpret_cast<sal_uInt64 *>( pRegisterReturn ) = gpReturn[0]; >>> + break; >>> + case typelib_TypeClass_LONG: >>> + case typelib_TypeClass_UNSIGNED_LONG: >>> + case typelib_TypeClass_ENUM: >>> + *reinterpret_cast<sal_uInt32 *>( pRegisterReturn ) = >>> *reinterpret_cast<sal_uInt32*>( &gpReturn[0] ); >>> + break; >>> + case typelib_TypeClass_CHAR: >>> + case typelib_TypeClass_SHORT: >>> + case typelib_TypeClass_UNSIGNED_SHORT: >>> + *reinterpret_cast<sal_uInt16 *>( pRegisterReturn ) = >>> *reinterpret_cast<sal_uInt16*>( &gpReturn[0] ); >>> + break; >>> + case typelib_TypeClass_BOOLEAN: >>> + case typelib_TypeClass_BYTE: >>> + *reinterpret_cast<sal_uInt8 *>( pRegisterReturn ) = >>> *reinterpret_cast<sal_uInt8*>( &gpReturn[0] ); >>> + break; >>> + case typelib_TypeClass_FLOAT: >>> + case typelib_TypeClass_DOUBLE: >>> + *reinterpret_cast<double *>( pRegisterReturn ) = fpReturn[0]; >>> + break; >>> + default: >>> + { >>> + sal_Int32 const nRetSize = pReturnTypeRef->pType->nSize; >>> + if (bSimpleReturn && nRetSize <= 16 && nRetSize > 0) >>> + { >>> + // Register-returned aggregate: an HFA arrives in d0..d3, a >>> + // non-HFA <= 16 bytes in x0,x1. fill_struct picks the >>> right one. >>> + aarch64::fill_struct( pReturnTypeRef, &gpReturn[0], >>> &fpReturn[0], pRegisterReturn); >>> + } >>> + break; >>> + } >>> + } >>> +} >>> + >>> +//================================================================================================== >>> + >>> +// Macros for easier insertion of values to registers or stack >>> +// pSV - pointer to the source >>> +// nr - order of the value [will be increased if stored to register] >>> +// pFPR, pGPR - pointer to the registers >>> +// pDS - pointer to the stack [will be increased if stored here] >>> + >>> +// The pFPR slot holds the value to be loaded into a v register; the >>> trampoline >>> +// loads it with LDR d<n>, so float and double are stored the same way >>> here. >>> +#define INSERT_FLOAT_DOUBLE( pSV, nr, pFPR, pDS ) \ >>> + if ( nr < aarch64::MAX_FPR_REGS ) \ >>> + pFPR[nr++] = *reinterpret_cast<double *>( pSV ); \ >>> + else \ >>> + *pDS++ = *reinterpret_cast<sal_uInt64 *>( pSV ); // verbatim! >>> + >>> +#define INSERT_INT64( pSV, nr, pGPR, pDS ) \ >>> + if ( nr < aarch64::MAX_GPR_REGS ) \ >>> + pGPR[nr++] = *reinterpret_cast<sal_uInt64 *>( pSV ); \ >>> + else \ >>> + *pDS++ = *reinterpret_cast<sal_uInt64 *>( pSV ); >>> + >>> +#define INSERT_INT32( pSV, nr, pGPR, pDS ) \ >>> + if ( nr < aarch64::MAX_GPR_REGS ) \ >>> + pGPR[nr++] = *reinterpret_cast<sal_uInt32 *>( pSV ); \ >>> + else \ >>> + *pDS++ = *reinterpret_cast<sal_uInt32 *>( pSV ); >>> + >>> +#define INSERT_INT16( pSV, nr, pGPR, pDS ) \ >>> + if ( nr < aarch64::MAX_GPR_REGS ) \ >>> + pGPR[nr++] = *reinterpret_cast<sal_uInt16 *>( pSV ); \ >>> + else \ >>> + *pDS++ = *reinterpret_cast<sal_uInt16 *>( pSV ); >>> + >>> +#define INSERT_INT8( pSV, nr, pGPR, pDS ) \ >>> + if ( nr < aarch64::MAX_GPR_REGS ) \ >>> + pGPR[nr++] = *reinterpret_cast<sal_uInt8 *>( pSV ); \ >>> + else \ >>> + *pDS++ = *reinterpret_cast<sal_uInt8 *>( pSV ); >>> + >>> +//================================================================================================== >>> + >>> +namespace { >>> + >>> +void appendCString(OUStringBuffer & buffer, char const * text) { >>> + if (text != 0) { >>> + buffer.append( >>> + OStringToOUString(OString(text), RTL_TEXTENCODING_ISO_8859_1)); >>> + // use 8859-1 to avoid conversion failure >>> + } >>> +} >>> + >>> +} >>> + >>> +static void cpp_call( >>> + bridges::cpp_uno::shared::UnoInterfaceProxy * pThis, >>> + bridges::cpp_uno::shared::VtableSlot aVtableSlot, >>> + typelib_TypeDescriptionReference * pReturnTypeRef, >>> + sal_Int32 nParams, typelib_MethodParameter * pParams, >>> + void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc ) >>> +{ >>> + // Maxium space for [complex ret ptr], values | ptr ... >>> + // (but will be used less - some of the values will be in pGPR and pFPR) >>> + sal_uInt64 *pStack = (sal_uInt64 *)__builtin_alloca( (nParams + 3) * >>> sizeof(sal_uInt64) ); >>> + sal_uInt64 *pStackStart = pStack; >>> + >>> + sal_uInt64 pGPR[aarch64::MAX_GPR_REGS]; >>> + sal_uInt32 nGPR = 0; >>> + >>> + double pFPR[aarch64::MAX_FPR_REGS]; >>> + sal_uInt32 nFPR = 0; >>> + >>> + // Return >>> + typelib_TypeDescription * pReturnTypeDescr = 0; >>> + TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef ); >>> + OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" ); >>> + >>> + void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion >>> (see below) >>> + >>> + // Indirect-result pointer. On AArch64 this is passed in the dedicated >>> x8 >>> + // register, NOT as the first general-purpose argument (unlike x86-64 >>> SysV). >>> + // So we do NOT insert it into pGPR here; it is threaded to the >>> trampoline >>> + // separately as pIndirectReturn. >>> + void * pIndirectReturn = 0; >>> + >>> + bool bSimpleReturn = true; >>> + if ( pReturnTypeDescr ) >>> + { >>> + if ( aarch64::return_in_hidden_param( pReturnTypeRef ) ) >>> + bSimpleReturn = false; >>> + >>> + if ( bSimpleReturn ) >>> + pCppReturn = pUnoReturn; // direct way for simple types >>> + else >>> + { >>> + // complex return via the x8 indirect-result buffer >>> + pCppReturn = >>> bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )? >>> + __builtin_alloca( >>> pReturnTypeDescr->nSize ) : pUnoReturn; >>> + pIndirectReturn = pCppReturn; >>> + } >>> + } >>> + >>> + // Push "this" pointer >>> + void * pAdjustedThisPtr = reinterpret_cast< void ** >( pThis->getCppI() >>> ) + aVtableSlot.offset; >>> + INSERT_INT64( &pAdjustedThisPtr, nGPR, pGPR, pStack ); >>> + >>> + // Args >>> + void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams ); >>> + // Indizes of values this have to be converted (interface conversion >>> cpp<=>uno) >>> + sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams); >>> + // Type descriptions for reconversions >>> + typelib_TypeDescription ** ppTempParamTypeDescr = >>> (typelib_TypeDescription **)(pCppArgs + (2 * nParams)); >>> + >>> + sal_Int32 nTempIndizes = 0; >>> + >>> + for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos ) >>> + { >>> + const typelib_MethodParameter & rParam = pParams[nPos]; >>> + typelib_TypeDescription * pParamTypeDescr = 0; >>> + TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef ); >>> + >>> + if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( >>> pParamTypeDescr )) >>> + { >>> + uno_copyAndConvertData( pCppArgs[nPos] = alloca( 8 ), >>> pUnoArgs[nPos], pParamTypeDescr, >>> + >>> pThis->getBridge()->getUno2Cpp() ); >>> + >>> + switch (pParamTypeDescr->eTypeClass) >>> + { >>> + case typelib_TypeClass_HYPER: >>> + case typelib_TypeClass_UNSIGNED_HYPER: >>> + INSERT_INT64( pCppArgs[nPos], nGPR, pGPR, >>> pStack ); >>> + break; >>> + case typelib_TypeClass_LONG: >>> + case typelib_TypeClass_UNSIGNED_LONG: >>> + case typelib_TypeClass_ENUM: >>> + INSERT_INT32( pCppArgs[nPos], nGPR, pGPR, >>> pStack ); >>> + break; >>> + case typelib_TypeClass_SHORT: >>> + case typelib_TypeClass_CHAR: >>> + case typelib_TypeClass_UNSIGNED_SHORT: >>> + INSERT_INT16( pCppArgs[nPos], nGPR, pGPR, >>> pStack ); >>> + break; >>> + case typelib_TypeClass_BOOLEAN: >>> + case typelib_TypeClass_BYTE: >>> + INSERT_INT8( pCppArgs[nPos], nGPR, pGPR, pStack >>> ); >>> + break; >>> + case typelib_TypeClass_FLOAT: >>> + case typelib_TypeClass_DOUBLE: >>> + INSERT_FLOAT_DOUBLE( pCppArgs[nPos], nFPR, >>> pFPR, pStack ); >>> + break; >>> + default: >>> + break; >>> + } >>> + >>> + // no longer needed >>> + TYPELIB_DANGER_RELEASE( pParamTypeDescr ); >>> + } >>> + else // ptr to complex value | ref >>> + { >>> + if (! rParam.bIn) // is pure out >>> + { >>> + // cpp out is constructed mem, uno out is not! >>> + uno_constructData( >>> + pCppArgs[nPos] = alloca( >>> pParamTypeDescr->nSize ), >>> + pParamTypeDescr ); >>> + pTempIndizes[nTempIndizes] = nPos; // default >>> constructed for cpp call >>> + // will be released at reconversion >>> + ppTempParamTypeDescr[nTempIndizes++] = >>> pParamTypeDescr; >>> + } >>> + // is in/inout >>> + else if >>> (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr )) >>> + { >>> + uno_copyAndConvertData( >>> + pCppArgs[nPos] = alloca( >>> pParamTypeDescr->nSize ), >>> + pUnoArgs[nPos], pParamTypeDescr, >>> pThis->getBridge()->getUno2Cpp() ); >>> + >>> + pTempIndizes[nTempIndizes] = nPos; // has to be >>> reconverted >>> + // will be released at reconversion >>> + ppTempParamTypeDescr[nTempIndizes++] = >>> pParamTypeDescr; >>> + } >>> + else // direct way >>> + { >>> + pCppArgs[nPos] = pUnoArgs[nPos]; >>> + // no longer needed >>> + TYPELIB_DANGER_RELEASE( pParamTypeDescr ); >>> + } >>> + INSERT_INT64( &(pCppArgs[nPos]), nGPR, pGPR, pStack ); >>> + } >>> + } >>> + >>> + try >>> + { >>> + try { >>> + callVirtualMethod( >>> + pAdjustedThisPtr, aVtableSlot.index, >>> + pCppReturn, pReturnTypeRef, bSimpleReturn, >>> + pIndirectReturn, >>> + pStackStart, ( pStack - pStackStart ), >>> + pGPR, nGPR, >>> + pFPR, nFPR ); >>> + } catch (Exception &) { >>> + throw; >>> + } catch (std::exception & e) { >>> + OUStringBuffer buf; >>> + buf.appendAscii(RTL_CONSTASCII_STRINGPARAM("C++ code threw ")); >>> + appendCString(buf, typeid(e).name()); >>> + buf.appendAscii(RTL_CONSTASCII_STRINGPARAM(": ")); >>> + appendCString(buf, e.what()); >>> + throw RuntimeException( >>> + buf.makeStringAndClear(), Reference< XInterface >()); >>> + } catch (...) { >>> + throw RuntimeException( >>> + OUString( >>> + RTL_CONSTASCII_USTRINGPARAM( >>> + "C++ code threw unknown exception")), >>> + Reference< XInterface >()); >>> + } >>> + >>> + // NO exception occurred... >>> + *ppUnoExc = 0; >>> + >>> + // reconvert temporary params >>> + for ( ; nTempIndizes--; ) >>> + { >>> + sal_Int32 nIndex = pTempIndizes[nTempIndizes]; >>> + typelib_TypeDescription * pParamTypeDescr = >>> ppTempParamTypeDescr[nTempIndizes]; >>> + >>> + if (pParams[nIndex].bIn) >>> + { >>> + if (pParams[nIndex].bOut) // inout >>> + { >>> + uno_destructData( pUnoArgs[nIndex], >>> pParamTypeDescr, 0 ); // destroy uno value >>> + uno_copyAndConvertData( >>> pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr, >>> + >>> pThis->getBridge()->getCpp2Uno() ); >>> + } >>> + } >>> + else // pure out >>> + { >>> + uno_copyAndConvertData( pUnoArgs[nIndex], >>> pCppArgs[nIndex], pParamTypeDescr, >>> + >>> pThis->getBridge()->getCpp2Uno() ); >>> + } >>> + // destroy temp cpp param => cpp: every param was >>> constructed >>> + uno_destructData( pCppArgs[nIndex], pParamTypeDescr, >>> cpp_release ); >>> + >>> + TYPELIB_DANGER_RELEASE( pParamTypeDescr ); >>> + } >>> + // return value >>> + if (pCppReturn && pUnoReturn != pCppReturn) >>> + { >>> + uno_copyAndConvertData( pUnoReturn, pCppReturn, >>> pReturnTypeDescr, >>> + >>> pThis->getBridge()->getCpp2Uno() ); >>> + uno_destructData( pCppReturn, pReturnTypeDescr, >>> cpp_release ); >>> + } >>> + } >>> + catch (...) >>> + { >>> + // fill uno exception >>> + fillUnoException( >>> CPPU_CURRENT_NAMESPACE::__cxa_get_globals()->caughtExceptions, *ppUnoExc, >>> pThis->getBridge()->getCpp2Uno() ); >>> + >>> + // temporary params >>> + for ( ; nTempIndizes--; ) >>> + { >>> + sal_Int32 nIndex = pTempIndizes[nTempIndizes]; >>> + // destroy temp cpp param => cpp: every param was >>> constructed >>> + uno_destructData( pCppArgs[nIndex], >>> ppTempParamTypeDescr[nTempIndizes], cpp_release ); >>> + TYPELIB_DANGER_RELEASE( >>> ppTempParamTypeDescr[nTempIndizes] ); >>> + } >>> + // return type >>> + if (pReturnTypeDescr) >>> + TYPELIB_DANGER_RELEASE( pReturnTypeDescr ); >>> + } >>> +} >>> + >>> +//================================================================================================== >>> + >>> +namespace bridges { namespace cpp_uno { namespace shared { >>> + >>> +void unoInterfaceProxyDispatch( >>> + uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr, >>> + void * pReturn, void * pArgs[], uno_Any ** ppException ) >>> +{ >>> + // is my surrogate >>> + bridges::cpp_uno::shared::UnoInterfaceProxy * pThis >>> + = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >>> >(pUnoI); >>> +#if OSL_DEBUG_LEVEL > 0 >>> + typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr; >>> +#endif >>> + >>> + switch (pMemberDescr->eTypeClass) >>> + { >>> + case typelib_TypeClass_INTERFACE_ATTRIBUTE: >>> + { >>> +#if OSL_DEBUG_LEVEL > 0 >>> + // determine vtable call index >>> + sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription >>> *)pMemberDescr)->nPosition; >>> + OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### member >>> pos out of range!" ); >>> +#endif >>> + VtableSlot aVtableSlot( >>> + getVtableSlot( >>> + reinterpret_cast< >>> + >>> typelib_InterfaceAttributeTypeDescription const * >( >>> + pMemberDescr))); >>> + >>> + if (pReturn) >>> + { >>> + // dependent dispatch >>> + cpp_call( >>> + pThis, aVtableSlot, >>> + ((typelib_InterfaceAttributeTypeDescription >>> *)pMemberDescr)->pAttributeTypeRef, >>> + 0, 0, // no params >>> + pReturn, pArgs, ppException ); >>> + } >>> + else >>> + { >>> + // is SET >>> + typelib_MethodParameter aParam; >>> + aParam.pTypeRef = >>> + ((typelib_InterfaceAttributeTypeDescription >>> *)pMemberDescr)->pAttributeTypeRef; >>> + aParam.bIn = sal_True; >>> + aParam.bOut = sal_False; >>> + >>> + typelib_TypeDescriptionReference * pReturnTypeRef = 0; >>> + OUString aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") >>> ); >>> + typelib_typedescriptionreference_new( >>> + &pReturnTypeRef, typelib_TypeClass_VOID, >>> aVoidName.pData ); >>> + >>> + // dependent dispatch >>> + aVtableSlot.index += 1; // get, then set method >>> + cpp_call( >>> + pThis, aVtableSlot, // get, then set method >>> + pReturnTypeRef, >>> + 1, &aParam, >>> + pReturn, pArgs, ppException ); >>> + >>> + typelib_typedescriptionreference_release( >>> pReturnTypeRef ); >>> + } >>> + >>> + break; >>> + } >>> + case typelib_TypeClass_INTERFACE_METHOD: >>> + { >>> +#if OSL_DEBUG_LEVEL > 0 >>> + // determine vtable call index >>> + sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription >>> *)pMemberDescr)->nPosition; >>> + OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### member >>> pos out of range!" ); >>> +#endif >>> + VtableSlot aVtableSlot( >>> + getVtableSlot( >>> + reinterpret_cast< >>> + typelib_InterfaceMethodTypeDescription >>> const * >( >>> + pMemberDescr))); >>> + >>> + switch (aVtableSlot.index) >>> + { >>> + // standard calls >>> + case 1: // acquire uno interface >>> + (*pUnoI->acquire)( pUnoI ); >>> + *ppException = 0; >>> + break; >>> + case 2: // release uno interface >>> + (*pUnoI->release)( pUnoI ); >>> + *ppException = 0; >>> + break; >>> + case 0: // queryInterface() opt >>> + { >>> + typelib_TypeDescription * pTD = 0; >>> + TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( >>> pArgs[0] )->getTypeLibType() ); >>> + if (pTD) >>> + { >>> + uno_Interface * pInterface = 0; >>> + (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)( >>> + pThis->getBridge()->getUnoEnv(), >>> + (void **)&pInterface, pThis->oid.pData, >>> (typelib_InterfaceTypeDescription *)pTD ); >>> + >>> + if (pInterface) >>> + { >>> + ::uno_any_construct( >>> + reinterpret_cast< uno_Any * >( pReturn ), >>> + &pInterface, pTD, 0 ); >>> + (*pInterface->release)( pInterface ); >>> + TYPELIB_DANGER_RELEASE( pTD ); >>> + *ppException = 0; >>> + break; >>> + } >>> + TYPELIB_DANGER_RELEASE( pTD ); >>> + } >>> + } // else perform queryInterface() >>> + default: >>> + // dependent dispatch >>> + cpp_call( >>> + pThis, aVtableSlot, >>> + ((typelib_InterfaceMethodTypeDescription >>> *)pMemberDescr)->pReturnTypeRef, >>> + ((typelib_InterfaceMethodTypeDescription >>> *)pMemberDescr)->nParams, >>> + ((typelib_InterfaceMethodTypeDescription >>> *)pMemberDescr)->pParams, >>> + pReturn, pArgs, ppException ); >>> + } >>> + break; >>> + } >>> + default: >>> + { >>> + ::com::sun::star::uno::RuntimeException aExc( >>> + OUString( RTL_CONSTASCII_USTRINGPARAM("illegal member >>> type description!") ), >>> + ::com::sun::star::uno::Reference< >>> ::com::sun::star::uno::XInterface >() ); >>> + >>> + Type const & rExcType = ::getCppuType( &aExc ); >>> + // binary identical null reference >>> + ::uno_type_any_construct( *ppException, &aExc, >>> rExcType.getTypeLibType(), 0 ); >>> + } >>> + } >>> +} >>> + >>> +} } } >>> diff --git a/main/configure.ac b/main/configure.ac >>> index 3f67e5b3fb..8731dc71f4 100644 >>> --- a/main/configure.ac >>> +++ b/main/configure.ac >>> @@ -922,8 +922,8 @@ AC_ARG_WITH(arm-target, >>> AC_ARG_WITH(macosx-target, >>> [ --macosx-target The minimal macOS/OSX deployment and build >>> target >>> >>> - Usage: --with-macosx-target=10.9 >>> -],with_macosx_target=$withval,with_macosx_target=10.9) >>> + Usage: --with-macosx-target=11.0 >>> +],with_macosx_target=$withval,with_macosx_target=11.0) >>> AC_ARG_WITH(macosx-sdk, >>> [ --macosx-sdk The macOS SDK to build against >>> >>> @@ -1159,9 +1159,29 @@ case "$build_os" in >>> fi >>> # Don't use OSVERSION until we know no conflicts result from it >>> _darwin_version="`uname -r | $AWK -F . '{ print $1 }'`" >>> - # FIXME: Assumes 10.x, breaks w/ Big Sur >>> - _osx_version="10.`expr $_darwin_version - 4`" >>> + # Map the Darwin (XNU) major version to the macOS version. >>> + # Darwin 6..19 => macOS 10.(darwin-4) (10.2 .. 10.15) >>> + # Darwin 20+ => macOS (darwin-9) (11, 12, 13, ...) >>> + if test "$_darwin_version" -ge 20; then >>> + _osx_version="`expr $_darwin_version - 9`" >>> + else >>> + _osx_version="10.`expr $_darwin_version - 4`" >>> + fi >>> AC_MSG_NOTICE([Detected Darwin version: $_darwin_version >>> ($_osx_version)]) >>> + # Detect the build CPU architecture. Apple Silicon (arm64) >>> reports >>> + # "arm64" from uname -m and maps to the aarch64 >>> toolchain/bridge. >>> + _darwin_cpu="`uname -m`" >>> + case "$_darwin_cpu" in >>> + arm64|aarch64) >>> + AC_MSG_NOTICE([Detected Apple Silicon (arm64) build host]) >>> + ;; >>> + x86_64|i*86) >>> + AC_MSG_NOTICE([Detected Intel (x86_64) build host]) >>> + ;; >>> + *) >>> + AC_MSG_ERROR([Unsupported macOS CPU architecture: >>> $_darwin_cpu]) >>> + ;; >>> + esac >>> ;; >>> os2*) >>> test_x=no >>> @@ -3907,10 +3927,20 @@ if test "$_os" = "Darwin"; then >>> sdk_target=$with_macosx_target >>> AC_MSG_CHECKING([checking SDK compatibility with OSX $sdk_target]) >>> >>> + sdk_major=`echo $sdk_target | cut -d"." -f1` >>> sdk_minor=`echo $sdk_target | cut -d"." -f2` >>> + test -z "$sdk_minor" && sdk_minor=0 >>> + >>> + dnl Minimum supported macOS is 11.0 (Big Sur). Pre-11 targets are only >>> + dnl accepted down to the old 10.9 floor for legacy Intel builds. >>> + if test "$_darwin_cpu" = "arm64" -o "$_darwin_cpu" = "aarch64"; then >>> + if test "$sdk_major" -lt "11"; then >>> + AC_MSG_ERROR([Apple Silicon (arm64) requires >>> --with-macosx-target=11.0 or later]) >>> + fi >>> + fi >>> >>> - if test "$sdk_minor" -lt "9"; then >>> - AC_MSG_ERROR([SDK version < 10.9 is not longer supported]) >>> + if test "$sdk_major" -lt "10" -o \( "$sdk_major" -eq "10" -a >>> "$sdk_minor" -lt "9" \); then >>> + AC_MSG_ERROR([macOS deployment target < 10.9 is no longer supported]) >>> else >>> MACOSX_DEPLOYMENT_TARGET=$sdk_target >>> sdk_path=$with_macosx_sdk >>> diff --git a/main/icu/icu4c-4_2_1-src.patch b/main/icu/icu4c-4_2_1-src.patch >>> index 77fc719528..572572a3ea 100644 >>> --- a/main/icu/icu4c-4_2_1-src.patch >>> +++ b/main/icu/icu4c-4_2_1-src.patch >>> @@ -212,7 +212,7 @@ diff -ru misc/icu/source/tools/genuca/genuca.cpp >>> misc/build/icu/source/tools/gen >>> + echo "${CC} ${CFLAGS} ${CPPFLAGS} ${LDFLAGS}" >>> case "${CC} ${CFLAGS} ${CPPFLAGS} ${LDFLAGS}" in #( >>> - *-arch*ppc*|*-arch*i386*|*-arch*x86_64*) ac_cv_c_bigendian=universal;; >>> -+ *-arch*i386*|*-arch*x86_64*) ac_cv_c_bigendian=no;; >>> ++ *-arch*i386*|*-arch*x86_64*|*-arch*arm64*|*-arch*aarch64*) >>> ac_cv_c_bigendian=no;; >>> + *-arch*ppc*) ac_cv_c_bigendian=yes;; >>> esac >>> else >>> diff --git a/main/jvmfwk/plugins/sunmajor/pluginlib/util.cxx >>> b/main/jvmfwk/plugins/sunmajor/pluginlib/util.cxx >>> index daec7fe94a..fbeb1ef201 100644 >>> --- a/main/jvmfwk/plugins/sunmajor/pluginlib/util.cxx >>> +++ b/main/jvmfwk/plugins/sunmajor/pluginlib/util.cxx >>> @@ -102,6 +102,12 @@ struct JavaSearchPathEntry { >>> struct JavaSearchPathEntry g_arSearchPaths[] = { >>> #ifdef MACOSX >>> { 0, "" }, >>> + // Modern macOS JDK location (Oracle/Temurin/etc., both arm64 and >>> x86_64 >>> + // install here). Each subdirectory is a JDK whose home is >>> Contents/Home, >>> + // so scan the immediate contents. A JDK of the wrong architecture >>> (e.g. a >>> + // Rosetta x86_64 JDK on Apple Silicon) is harmlessly skipped when its >>> + // libjvm.dylib fails to load into the native-arch process. >>> + { 1, "Library/Java/JavaVirtualMachines/" }, >>> { 0, "Library/Internet >>> Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin" }, >>> { 0, "System/Library/Frameworks/JavaVM.framework/Versions/1.4.2/" }, >>> #else >>> @@ -1245,6 +1251,14 @@ void >>> createJavaInfoDirScan(vector<rtl::Reference<VendorBase> >& vecInfos) >>> OUSTR(" is a Java. \n")); >>> >>> getJREInfoByPath(aStatus.getFileURL(),vecInfos); >>> +#ifdef MACOSX >>> + // On macOS a JDK bundle's home is at >>> <bundle>/Contents/Home >>> + // (e.g. under >>> /Library/Java/JavaVirtualMachines/<jdk>/), >>> + // not the bundle directory itself, so also probe >>> there. >>> + getJREInfoByPath( >>> + aStatus.getFileURL() + >>> + OUSTR("/Contents/Home"), vecInfos); >>> +#endif >>> } >>> >>> JFW_ENSURE(errNext == File::E_None || errNext == >>> File::E_NOENT, >>> diff --git a/main/openssl/makefile.mk b/main/openssl/makefile.mk >>> index cecba9e26e..a5662eabea 100644 >>> --- a/main/openssl/makefile.mk >>> +++ b/main/openssl/makefile.mk >>> @@ -107,8 +107,12 @@ UNAME=$(shell uname) >>> .ENDIF >>> >>> .IF "$(OS)" == "MACOSX" >>> +.IF "$(CPUNAME)" == "AARCH64" >>> + CONFIGURE_ACTION=Configure darwin64-arm64-cc no-dso no-shared $(NO_ASM) >>> +.ELSE >>> CONFIGURE_ACTION=Configure darwin64-x86_64-cc no-dso no-shared $(NO_ASM) >>> .ENDIF >>> +.ENDIF >>> >>> .IF "$(OS)" == "WNT" >>> >>> diff --git a/main/python/pyversion.mk b/main/python/pyversion.mk >>> index 353925e92e..95f7b299da 100644 >>> --- a/main/python/pyversion.mk >>> +++ b/main/python/pyversion.mk >>> @@ -20,8 +20,8 @@ >>> # ************************************************************* >>> # when you want to change the python version, you must update the d.lst >>> # in the python project accordingly !!! >>> -PYMAJOR=2 >>> -PYMINOR=7 >>> +PYMAJOR=3 >>> +PYMINOR=10 >>> PYMICRO=18 >>> PYVERSION=$(PYMAJOR).$(PYMINOR).$(PYMICRO) >>> >>> diff --git a/main/python/pyversion_dmake.mk b/main/python/pyversion_dmake.mk >>> index 37aa099277..b8252a9767 100644 >>> --- a/main/python/pyversion_dmake.mk >>> +++ b/main/python/pyversion_dmake.mk >>> @@ -20,8 +20,8 @@ >>> # ************************************************************* >>> # when you want to change the python version, you must update the d.lst >>> # in the python project accordingly !!! >>> -PYMAJOR=2 >>> -PYMINOR=7 >>> +PYMAJOR=3 >>> +PYMINOR=10 >>> PYMICRO=18 >>> PYVERSION=$(PYMAJOR).$(PYMINOR).$(PYMICRO) >>> >>> diff --git a/main/pyuno/source/loader/pythonloader.py >>> b/main/pyuno/source/loader/pythonloader.py >>> index 46e051da98..34ff1c532b 100644 >>> --- a/main/pyuno/source/loader/pythonloader.py >>> +++ b/main/pyuno/source/loader/pythonloader.py >>> @@ -21,7 +21,7 @@ >>> import uno >>> import unohelper >>> import sys >>> -import imp >>> +import types >>> import os >>> from com.sun.star.uno import Exception,RuntimeException >>> from com.sun.star.loader import XImplementationLoader >>> @@ -84,14 +84,14 @@ class Loader( XImplementationLoader, XServiceInfo, >>> unohelper.Base ): >>> # did we load the module already ? >>> mod = g_loadedComponents.get( url ) >>> if not mod: >>> - mod = imp.new_module("uno_component") >>> + mod = types.ModuleType("uno_component") >>> >>> # check for pythonpath.zip beside .py files >>> checkForPythonPathBesideComponent( >>> url[0:url.rfind('/')] ) >>> >>> # read the file >>> filename = unohelper.fileUrlToSystemPath( url ) >>> - fileHandle = file( filename ) >>> + fileHandle = open( filename ) >>> src = fileHandle.read().replace("\r","") >>> if not src.endswith( "\n" ): >>> src = src + "\n" >>> diff --git a/main/sal/osl/unx/interlck.c b/main/sal/osl/unx/interlck.c >>> index cfcea0fbc0..d24db7b341 100644 >>> --- a/main/sal/osl/unx/interlck.c >>> +++ b/main/sal/osl/unx/interlck.c >>> @@ -178,6 +178,29 @@ oslInterlockedCount SAL_CALL >>> osl_decrementInterlockedCount(oslInterlockedCount* >>> #endif >>> } >>> >>> +#elif (defined(__GNUC__) || defined(__clang__)) && defined ( AARCH64 ) >>> +/* AArch64 (ARM 64-bit, e.g. Apple Silicon). Use the compiler's atomic >>> + built-ins, which clang/gcc lower to the AArch64 >>> load-exclusive/store-exclusive >>> + (ldaxr/stlxr) sequence, or to LSE atomics (ldadd) on ARMv8.1+. This >>> avoids the >>> + global-mutex fallback below. __sync_*_and_fetch are full-barrier and >>> return >>> + the new value, matching the required semantics. */ >>> + >>> +/*****************************************************************************/ >>> +/* osl_incrementInterlockedCount */ >>> +/*****************************************************************************/ >>> +oslInterlockedCount SAL_CALL >>> osl_incrementInterlockedCount(oslInterlockedCount* pCount) >>> +{ >>> + return __sync_add_and_fetch( pCount, 1 ); >>> +} >>> + >>> +/*****************************************************************************/ >>> +/* osl_decrementInterlockedCount */ >>> +/*****************************************************************************/ >>> +oslInterlockedCount SAL_CALL >>> osl_decrementInterlockedCount(oslInterlockedCount* pCount) >>> +{ >>> + return __sync_sub_and_fetch( pCount, 1 ); >>> +} >>> + >>> #else >>> /* use only if nothing else works, expensive due to single mutex for all >>> reference counts */ >>> >>> diff --git a/main/sal/rtl/source/macro.hxx b/main/sal/rtl/source/macro.hxx >>> index 10948868f3..4aee4358aa 100644 >>> --- a/main/sal/rtl/source/macro.hxx >>> +++ b/main/sal/rtl/source/macro.hxx >>> @@ -77,6 +77,8 @@ this is inserted for the case that the preprocessor >>> ignores error >>> # else >>> # define THIS_ARCH "MIPS_EL" >>> # endif >>> +#elif defined AARCH64 >>> +# define THIS_ARCH "AARCH64" >>> #elif defined ARM >>> # ifdef __ARM_EABI__ >>> # define THIS_ARCH "ARM_EABI" >>> diff --git a/main/scripting/source/pyprov/mailmerge.py >>> b/main/scripting/source/pyprov/mailmerge.py >>> index 4a4c430c28..c11ddd8c7a 100644 >>> --- a/main/scripting/source/pyprov/mailmerge.py >>> +++ b/main/scripting/source/pyprov/mailmerge.py >>> @@ -54,13 +54,13 @@ from com.sun.star.lang import IllegalArgumentException >>> from com.sun.star.lang import EventObject >>> from com.sun.star.mail import SendMailMessageFailedException >>> >>> -from email.MIMEBase import MIMEBase >>> -from email.Message import Message >>> -from email import Encoders >>> -from email.Header import Header >>> -from email.MIMEMultipart import MIMEMultipart >>> -from email.Utils import formatdate >>> -from email.Utils import parseaddr >>> +from email.mime.base import MIMEBase >>> +from email.message import Message >>> +from email import encoders >>> +from email.header import Header >>> +from email.mime.multipart import MIMEMultipart >>> +from email.utils import formatdate >>> +from email.utils import parseaddr >>> from socket import _GLOBAL_DEFAULT_TIMEOUT >>> >>> import sys, smtplib, imaplib, poplib >>> @@ -245,7 +245,7 @@ class PyMailSMTPService(unohelper.Base, XSmtpService): >>> msgattachment = MIMEBase(maintype, subtype) >>> data = content.getTransferData(flavor) >>> msgattachment.set_payload(data) >>> - Encoders.encode_base64(msgattachment) >>> + encoders.encode_base64(msgattachment) >>> fname = attachment.ReadableName >>> try: >>> fname.encode('ascii') >>> diff --git a/main/scripting/source/pyprov/pythonscript.py >>> b/main/scripting/source/pyprov/pythonscript.py >>> index 4e7fc4667e..03f52b897a 100644 >>> --- a/main/scripting/source/pyprov/pythonscript.py >>> +++ b/main/scripting/source/pyprov/pythonscript.py >>> @@ -24,7 +24,7 @@ import uno >>> import unohelper >>> import sys >>> import os >>> -import imp >>> +import types >>> import time >>> import ast >>> >>> @@ -356,7 +356,7 @@ class ScriptContext(unohelper.Base): >>> # code = readTextFromStream( sfa.openFileRead( url ) ) >>> >>> # execute the module >>> -# entry = ModuleEntry( lastRead, >>> imp.new_module("ooo_script_framework") ) >>> +# entry = ModuleEntry( lastRead, >>> types.ModuleType("ooo_script_framework") ) >>> # entry.module.__dict__[GLOBAL_SCRIPTCONTEXT_NAME] = g_scriptContext >>> # entry.module.__file__ = url >>> # exec code in entry.module.__dict__ >>> @@ -489,7 +489,7 @@ class ProviderContext: >>> src = ensureSourceState( src ) >>> >>> # execute the module >>> - entry = ModuleEntry( lastRead, >>> imp.new_module("ooo_script_framework") ) >>> + entry = ModuleEntry( lastRead, >>> types.ModuleType("ooo_script_framework") ) >>> entry.module.__dict__[GLOBAL_SCRIPTCONTEXT_NAME] = >>> self.scriptContext >>> >>> code = None >>> @@ -666,7 +666,7 @@ class ScriptBrowseNode( unohelper.Base, XBrowseNode, >>> XPropertySet, XInvocation, >>> if event.ActionCommand == "Run": >>> code = self.editor.getControl("EditorTextField").getText() >>> code = ensureSourceState( code ) >>> - mod = imp.new_module("ooo_script_framework") >>> + mod = types.ModuleType("ooo_script_framework") >>> mod.__dict__[GLOBAL_SCRIPTCONTEXT_NAME] = >>> self.provCtx.scriptContext >>> exec(code, mod.__dict__) >>> values = mod.__dict__.get( CALLABLE_CONTAINER_NAME , None ) >>> @@ -827,7 +827,7 @@ class FileBrowseNode( unohelper.Base, XBrowseNode, >>> XPropertySet, XInvocation, XA >>> if event.ActionCommand == "Run": >>> code = self.editor.getControl("EditorTextField").getText() >>> code = ensureSourceState( code ) >>> - mod = imp.new_module("ooo_script_framework") >>> + mod = types.ModuleType("ooo_script_framework") >>> mod.__dict__[GLOBAL_SCRIPTCONTEXT_NAME] = >>> self.provCtx.scriptContext >>> exec(code, mod.__dict__) >>> values = mod.__dict__.get( CALLABLE_CONTAINER_NAME , None ) >>> diff --git a/main/set_soenv.in b/main/set_soenv.in >>> index 189b6afdfe..6812905f8e 100644 >>> --- a/main/set_soenv.in >>> +++ b/main/set_soenv.in >>> @@ -807,6 +807,14 @@ elsif ( $platform =~ m/darwin/ ) >>> $CPUNAME = "X86_64"; >>> $OUTPATH = "unxmaccx"; >>> } >>> + elsif ($platform =~ m/^(aarch64|arm64)/) >>> + { >>> + print "Setting values for MacOSX/Darwin on aarch64 (Apple >>> Silicon)... "; >>> + $outfile = "MacOSXAARCH64Env.Set"; >>> + $CPU = "R"; >>> + $CPUNAME = "AARCH64"; >>> + $OUTPATH = "unxmaccr"; >>> + } >>> else >>> { >>> print "\nset_soenv: Unknown MacOSX/Darwin platform: $platform\n"; >>> diff --git a/main/setup_native/source/mac/Info.plist.langpack >>> b/main/setup_native/source/mac/Info.plist.langpack >>> index 0e12cc1c19..80ad91f30b 100644 >>> --- a/main/setup_native/source/mac/Info.plist.langpack >>> +++ b/main/setup_native/source/mac/Info.plist.langpack >>> @@ -23,7 +23,7 @@ >>> <plist version="1.0"> >>> <dict> >>> <key>LSMinimumSystemVersion</key> >>> - <string>10.7.0</string> >>> + <string>11.0</string> >>> <key>CFBundleDevelopmentRegion</key> >>> <string>English</string> >>> <!-- UTI declarations for OS X >= 10.4 --> >>> diff --git a/main/solenv/bin/modules/installer/download.pm >>> b/main/solenv/bin/modules/installer/download.pm >>> index 6605bbdbc6..6ad1570ab0 100644 >>> --- a/main/solenv/bin/modules/installer/download.pm >>> +++ b/main/solenv/bin/modules/installer/download.pm >>> @@ -607,6 +607,10 @@ sub get_download_architecture >>> { >>> $arch = "x86-64"; >>> } >>> + elsif ( $installer::globals::compiler =~ /^unxmaccr/ ) >>> + { >>> + $arch = "aarch64"; >>> + } >>> elsif ( $installer::globals::issolarissparcbuild ) >>> { >>> $arch = "Sparc"; >>> diff --git a/main/solenv/bin/modules/installer/worker.pm >>> b/main/solenv/bin/modules/installer/worker.pm >>> index 0d387a3e33..ef22a34e2a 100644 >>> --- a/main/solenv/bin/modules/installer/worker.pm >>> +++ b/main/solenv/bin/modules/installer/worker.pm >>> @@ -2280,6 +2280,10 @@ sub get_platform_name >>> { >>> $platformname = "MacOSXX86-64"; >>> } >>> + elsif ( $installer::globals::compiler =~ /^unxmaccr/ ) >>> + { >>> + $platformname = "MacOSXAArch64"; >>> + } >>> elsif ( $installer::globals::compiler =~ /^unxmacxp/ ) >>> { >>> $platformname = "MacOSXPowerPC"; >>> diff --git a/main/solenv/bin/modules/osarch.pm >>> b/main/solenv/bin/modules/osarch.pm >>> index 4ded37ed15..1093b81a27 100644 >>> --- a/main/solenv/bin/modules/osarch.pm >>> +++ b/main/solenv/bin/modules/osarch.pm >>> @@ -102,7 +102,9 @@ chop( $m_str, $s_str ); >>> "IP22", "mips", # voyager >>> "IP32", "mips", # giotto >>> "Power Macintosh", "ppc", >>> # NetBSD/arm32 >>> - "arm32", "arm32" >>> # NetBSD/arm32 >>> + "arm32", "arm32", >>> # NetBSD/arm32 >>> + "arm64", "aarch64", >>> # macOS Apple Silicon (uname -m) >>> + "aarch64", "aarch64" # Linux >>> aarch64 >>> ); >>> >>> %archDefTable=("sun4c", "-DSPARC -DSUN -DSUN4", # hawai >>> @@ -130,7 +132,9 @@ chop( $m_str, $s_str ); >>> "IP22", "-DMIPS", # >>> voyager >>> "IP32", "-DMIPS", # giotto >>> "Power Macintosh", "-DPPC", >>> # NetBSD/arm32 >>> - "arm32", "-DARM32" >>> # NetBSD/arm32 >>> + "arm32", "-DARM32", >>> # NetBSD/arm32 >>> + "arm64", "-DAARCH64", >>> # macOS Apple Silicon (uname -m) >>> + "aarch64", "-DAARCH64" # Linux >>> aarch64 >>> ); >>> >>> %archDosTable=("sun4c", "s", # hawai >>> @@ -158,7 +162,9 @@ chop( $m_str, $s_str ); >>> "IP22", "m", # voyager >>> "IP32", "m", # giotto >>> "Power Macintosh", "p", >>> # NetBSD/arm32 >>> - "arm32", "a" >>> # NetBSD/arm32 >>> + "arm32", "a", >>> # NetBSD/arm32 >>> + "arm64", "r", >>> # macOS Apple Silicon (uname -m) >>> + "aarch64", "r" # Linux >>> aarch64 >>> ); >>> >>> $main::solarDef = $osDefTable{ $s_str }.' '.$archDefTable{ >>> $m_str }; >>> diff --git a/main/solenv/bin/update_module_ignore_lists.pl >>> b/main/solenv/bin/update_module_ignore_lists.pl >>> index 3a827d743f..f7eecef05d 100644 >>> --- a/main/solenv/bin/update_module_ignore_lists.pl >>> +++ b/main/solenv/bin/update_module_ignore_lists.pl >>> @@ -47,6 +47,7 @@ my @platforms = ( >>> "unxmacxp", >>> "unxmacci", >>> "unxmaccx", >>> + "unxmaccr", >>> "unxubit8", >>> "unxaixp", >>> "unxbsda", >>> diff --git a/main/solenv/gbuild/platform/macosx.mk >>> b/main/solenv/gbuild/platform/macosx.mk >>> index 3b5d65805a..b9501be453 100644 >>> --- a/main/solenv/gbuild/platform/macosx.mk >>> +++ b/main/solenv/gbuild/platform/macosx.mk >>> @@ -64,6 +64,8 @@ ifeq ($(CPUNAME),POWERPC) >>> gb_CPUDEFS += -DPOWERPC -DPPC >>> else ifeq ($(CPUNAME),INTEL) >>> gb_CPUDEFS += -DX86 >>> +else ifeq ($(CPUNAME),AARCH64) >>> +gb_CPUDEFS += -DARM64 >>> endif >>> >>> ifeq ($(strip $(SYSBASE)),) >>> diff --git a/main/solenv/inc/unx.mk b/main/solenv/inc/unx.mk >>> index f956e43a82..b5b4731cd6 100644 >>> --- a/main/solenv/inc/unx.mk >>> +++ b/main/solenv/inc/unx.mk >>> @@ -160,6 +160,10 @@ >>> .INCLUDE : unxmaccx.mk >>> .ENDIF >>> >>> +.IF "$(COM)$(OS)$(CPU)" == "CLANGMACOSXR" >>> +.INCLUDE : unxmaccr.mk >>> +.ENDIF >>> + >>> .IF "$(OS)$(CPU)" == "LINUXM" >>> .INCLUDE : unxlngmips.mk >>> .ENDIF >>> diff --git a/main/solenv/inc/unxmaccr.mk b/main/solenv/inc/unxmaccr.mk >>> new file mode 100644 >>> index 0000000000..0fdf36cc2d >>> --- /dev/null >>> +++ b/main/solenv/inc/unxmaccr.mk >>> @@ -0,0 +1,42 @@ >>> +#************************************************************** >>> +# >>> +# Licensed to the Apache Software Foundation (ASF) under one >>> +# or more contributor license agreements. See the NOTICE file >>> +# distributed with this work for additional information >>> +# regarding copyright ownership. The ASF licenses this file >>> +# to you under the Apache License, Version 2.0 (the >>> +# "License"); you may not use this file except in compliance >>> +# with the License. You may obtain a copy of the License at >>> +# >>> +# http://www.apache.org/licenses/LICENSE-2.0 >>> +# >>> +# Unless required by applicable law or agreed to in writing, >>> +# software distributed under the License is distributed on an >>> +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY >>> +# KIND, either express or implied. See the License for the >>> +# specific language governing permissions and limitations >>> +# under the License. >>> +# >>> +#************************************************************** >>> + >>> +# Mac OSX aarch64 (Apple Silicon) specific defines >>> + >>> +PROCESSOR_DEFINES=-DAARCH64 >>> +BUILD64=1 >>> + >>> +DLLPOSTFIX= >>> + >>> +# Build explicitly for arm64. Use conditional assignment (*=) so the value >>> can >>> +# still be overridden by exporting ARCH_FLAGS in the environment. >>> unxmacc.mk >>> +# also declares ARCH_FLAGS*= (empty), which becomes a no-op once set here. >>> +ARCH_FLAGS*=-arch arm64 >>> + >>> +# flags to enable build with symbols; required by crashdump feature >>> +.IF "$(ENABLE_SYMBOLS)"=="SMALL" >>> +CFLAGSENABLESYMBOLS=-g1 >>> +.ELSE >>> +CFLAGSENABLESYMBOLS=-g >>> +.ENDIF >>> + >>> +# Include generic Mac OS X makefile >>> +.INCLUDE : unxmacc.mk >>> diff --git a/main/source_soenv.sh b/main/source_soenv.sh >>> index 9d522c359f..ce87621c36 100644 >>> --- a/main/source_soenv.sh >>> +++ b/main/source_soenv.sh >>> @@ -108,6 +108,9 @@ else >>> i[3456]86-*-darwin*|x86_64-*-darwin*) >>> . ./MacOSXX64Env.Set.sh >>> ;; >>> + aarch64-*-darwin*|arm64-*-darwin*) >>> + . ./MacOSXAARCH64Env.Set.sh >>> + ;; >>> powerpc-*-darwin*) >>> . ./MacOSXPPCEnv.Set.sh >>> ;; >>> diff --git a/main/sysui/desktop/macosx/Info.plist >>> b/main/sysui/desktop/macosx/Info.plist >>> index d26d4251fe..9ffda6b8fa 100644 >>> --- a/main/sysui/desktop/macosx/Info.plist >>> +++ b/main/sysui/desktop/macosx/Info.plist >>> @@ -23,7 +23,7 @@ >>> <plist version="1.0"> >>> <dict> >>> <key>LSMinimumSystemVersion</key> >>> - <string>10.7.0</string> >>> + <string>11.0</string> >>> <key>CFBundleDevelopmentRegion</key> >>> <string>English</string> >>> <!-- UTI declarations for OS X >= 10.4 --> >>> >> >> --------------------------------------------------------------------- >> To unsubscribe, e-mail: [email protected] >> For additional commands, e-mail: [email protected] >> > > --------------------------------------------------------------------- > To unsubscribe, e-mail: [email protected] > For additional commands, e-mail: [email protected] > -- Jim "This is an outrage!" Tony Harrison
