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

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

commit 9c15e1abd703a7953928d7a80655ae1a76a41f6d
Author: Pedro Giffuni <[email protected]>
AuthorDate: Sat Sep 12 00:25:13 2026 -0500

    freebsd_aarch64: Initial support for FreeBSD ARM64
    
    This is early WIP, based on the macOS Silicon port. It is made available
    only because it is easier to get working once there is a rough sketch.
    
    Produced by Code Copilot.
---
 main/bridges/Library_cpp_uno.mk                    |  15 +
 .../source/cpp_uno/gcc3_freebsd_aarch64/abi.cxx    | 312 +++++++++++++++
 .../source/cpp_uno/gcc3_freebsd_aarch64/abi.hxx    |  96 +++++
 .../source/cpp_uno/gcc3_freebsd_aarch64/call.s     | 197 +++++++++
 .../cpp_uno/gcc3_freebsd_aarch64/cpp2uno.cxx       | 438 +++++++++++++++++++++
 .../source/cpp_uno/gcc3_freebsd_aarch64/except.cxx | 253 ++++++++++++
 .../cpp_uno/gcc3_freebsd_aarch64/makefile.mk       |  75 ++++
 .../source/cpp_uno/gcc3_freebsd_aarch64/share.hxx  |  65 +++
 .../cpp_uno/gcc3_freebsd_aarch64/uno2cpp.cxx       | 189 +++++++++
 9 files changed, 1640 insertions(+)

diff --git a/main/bridges/Library_cpp_uno.mk b/main/bridges/Library_cpp_uno.mk
index 0d8525362a..e3bce187d3 100644
--- a/main/bridges/Library_cpp_uno.mk
+++ b/main/bridges/Library_cpp_uno.mk
@@ -156,6 +156,21 @@ $(eval $(call gb_Library_add_asmobjects,$(COMNAME)_uno,\
        bridges/source/cpp_uno/gcc3_freebsd_x86-64/call \
 ))
 
+###########################################################
+else ifeq ($(OS)-$(CPUNAME)-$(COMNAME),FREEBSD-AARCH64-gcc3)
+###########################################################
+
+$(eval $(call gb_Library_add_exception_objects,$(COMNAME)_uno,\
+       bridges/source/cpp_uno/gcc3_freebsd_aarch64/abi \
+       bridges/source/cpp_uno/gcc3_freebsd_aarch64/except \
+       bridges/source/cpp_uno/gcc3_freebsd_aarch64/cpp2uno \
+       bridges/source/cpp_uno/gcc3_freebsd_aarch64/uno2cpp \
+))
+
+$(eval $(call gb_Library_add_asmobjects,$(COMNAME)_uno,\
+       bridges/source/cpp_uno/gcc3_freebsd_aarch64/call \
+))
+
 #########################################################
 else ifeq ($(OS)-$(CPUNAME)-$(COMNAME),LINUX-ALPHA_-gcc3)
 #########################################################
diff --git a/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/abi.cxx 
b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/abi.cxx
new file mode 100644
index 0000000000..71b8692f79
--- /dev/null
+++ b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/abi.cxx
@@ -0,0 +1,312 @@
+/*
+ * 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).
+//
+// 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.
+
+#include "abi.hxx"
+
+#include "bridges/cpp_uno/shared/types.hxx"
+
+#include <rtl/ustring.hxx>
+#include <string.h>
+
+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;
+}
+
+bool isComplexAggregate( typelib_TypeDescriptionReference *pTypeRef )
+{
+       typelib_TypeDescription * pTypeDescr = 0;
+       TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
+       const typelib_CompoundTypeDescription *pComp =
+               reinterpret_cast<const typelib_CompoundTypeDescription *>( 
pTypeDescr );
+       bool complex = pComp->pBaseTypeDescription != 0 &&
+               isComplexAggregate( pComp->pBaseTypeDescription->aBase.pWeakRef 
);
+       for ( sal_Int32 i = 0; !complex && i < pComp->nMembers; ++i )
+       {
+               typelib_TypeClass typeClass = pComp->ppTypeRefs[i]->eTypeClass;
+               if ( typeClass == typelib_TypeClass_STRUCT ||
+                        typeClass == typelib_TypeClass_EXCEPTION )
+                       complex = isComplexAggregate( pComp->ppTypeRefs[i] );
+               else
+                       complex = !bridges::cpp_uno::shared::isSimpleType( 
typeClass );
+       }
+       TYPELIB_DANGER_RELEASE( pTypeDescr );
+       return complex;
+}
+
+// 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 );
+
+                       // rCount is cumulative over the whole recursion, so 
remember where
+                       // this aggregate started in order to size-check it 
below.
+                       const int nCountAtEntry = rCount;
+                       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 );
+
+                       if ( bOk )
+                       {
+                               // Reject anything the elements do not tile 
exactly: only the
+                               // elements contributed by THIS aggregate count 
towards its size.
+                               sal_Int32 elementSize = rKind == HFA_FLOAT ? 4 
: 8;
+                               bOk = pTypeDescr->nSize ==
+                                       ( rCount - nCountAtEntry ) * 
elementSize;
+                               for ( sal_Int32 i = 0; bOk && i < 
pComp->nMembers; ++i )
+                                       bOk = pComp->pMemberOffsets[i] % 
elementSize == 0;
+                       }
+
+                       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 )
+       {
+               nUsedFPR = count;
+               nUsedGPR = 0;
+               return true; // HFA passed in consecutive FP regs
+       }
+
+       // Not HFA: if bigger than 16 bytes, pass indirectly.
+       typelib_TypeDescription * pTypeDescr = 0;
+       TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
+       if ( pTypeDescr->nSize > 16 )
+       {
+               TYPELIB_DANGER_RELEASE( pTypeDescr );
+               nUsedGPR = nUsedFPR = 0;
+               return false; // indirect
+       }
+
+       // small aggregate: it occupies 1 or 2 GPRs depending on size
+       nUsedFPR = 0;
+       nUsedGPR = ( pTypeDescr->nSize + 7 ) / 8;
+       if ( nUsedGPR < 1 ) nUsedGPR = 1;
+       TYPELIB_DANGER_RELEASE( pTypeDescr );
+       return true;
+}
+
+} // anonymous namespace
+
+// Public API implementations.
+namespace aarch64
+{
+
+bool examine_argument( typelib_TypeDescriptionReference *pTypeRef, bool 
bInReturn, int &nUsedGPR, int &nUsedFPR )
+{
+       // For returns, the hidden param rule uses >16 bytes for aggregates.
+       if ( pTypeRef->eTypeClass == typelib_TypeClass_STRUCT || 
pTypeRef->eTypeClass == typelib_TypeClass_EXCEPTION )
+       {
+               return classifyAggregate( pTypeRef, nUsedGPR, nUsedFPR );
+       }
+
+       // Scalars: floats -> FPR, others -> GPR
+       switch ( pTypeRef->eTypeClass )
+       {
+               case typelib_TypeClass_FLOAT:
+                       nUsedFPR = 1; nUsedGPR = 0; return true;
+               case typelib_TypeClass_DOUBLE:
+                       nUsedFPR = 1; nUsedGPR = 0; return true;
+               default:
+                       nUsedFPR = 0; nUsedGPR = 1; return true;
+       }
+}
+
+bool return_in_hidden_param( typelib_TypeDescriptionReference *pTypeRef )
+{
+       if ( pTypeRef->eTypeClass == typelib_TypeClass_STRUCT || 
pTypeRef->eTypeClass == typelib_TypeClass_EXCEPTION )
+       {
+               typelib_TypeDescription * pTypeDescr = 0;
+               TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
+               bool ret = pTypeDescr->nSize > 16;
+               TYPELIB_DANGER_RELEASE( pTypeDescr );
+               return ret;
+       }
+       return false; // scalars and small aggregates return in registers
+}
+
+sal_uInt32 get_return_kind( typelib_TypeDescriptionReference *pTypeRef )
+{
+       if ( pTypeRef->eTypeClass == typelib_TypeClass_FLOAT )
+               return typelib_TypeClass_FLOAT;
+
+       if ( pTypeRef->eTypeClass == typelib_TypeClass_DOUBLE )
+               return typelib_TypeClass_DOUBLE;
+
+       if ( pTypeRef->eTypeClass == typelib_TypeClass_STRUCT ||
+                pTypeRef->eTypeClass == typelib_TypeClass_EXCEPTION )
+       {
+               HfaKind kind = HFA_NONE;
+               int count = 0;
+
+               if ( collectHfa( pTypeRef, kind, count ) )
+               {
+                       if ( kind == HFA_FLOAT )
+                               return RETURN_KIND_HFA_FLOAT;
+
+                       if ( kind == HFA_DOUBLE )
+                               return RETURN_KIND_HFA_DOUBLE;
+               }
+       }
+
+       return pTypeRef->eTypeClass;
+}
+
+void fill_struct( typelib_TypeDescriptionReference *pTypeRef, const 
sal_uInt64* pGPR, const double* pFPR, void *pStruct )
+{
+       // For small aggregates, copy from GPR slots; for HFAs, copy from FPR 
slots.
+       if ( pTypeRef->eTypeClass == typelib_TypeClass_STRUCT || 
pTypeRef->eTypeClass == typelib_TypeClass_EXCEPTION )
+       {
+               int nGPR=0, nFPR=0;
+               if ( classifyAggregate( pTypeRef, nGPR, nFPR ) )
+               {
+                       if ( nFPR > 0 )
+                       {
+                       // HFA: copy elements from FPR slots. For FLOAT HFAs 
each element is
+                       // 4 bytes but occupies an 8-byte saved slot; copy each 
float from the
+                       // low 4 bytes of the corresponding double-sized slot. 
DOUBLE HFAs
+                       // can be copied directly.
+                       HfaKind kind = HFA_NONE;
+                       int count = 0;
+                       if ( collectHfa( pTypeRef, kind, count ) && kind == 
HFA_FLOAT )
+                       {
+                               for ( int i = 0; i < nFPR; ++i )
+                                       memcpy(
+                                               static_cast<char *>( pStruct ) 
+ i * sizeof(float),
+                                               reinterpret_cast<const char *>( 
pFPR) + i * sizeof(double),
+                                               sizeof(float) );
+                       }
+                       else
+                       {
+                               memcpy( pStruct, pFPR, nFPR * sizeof(double) );
+                       }
+                       }
+                       else
+                       {
+                               memcpy( pStruct, pGPR, nGPR * 
sizeof(sal_uInt64) );
+                       }
+               }
+       }
+}
+
+sal_uInt32 align_stack_offset( sal_uInt32 offset, 
typelib_TypeDescriptionReference *pTypeRef )
+{
+       // AArch64 stack overflow area is packed; align to natural alignment of 
the type (8)
+       const sal_uInt32 align = 8;
+       return ( offset + align - 1 ) & ~( align - 1 );
+}
+
+sal_uInt32 stack_size( typelib_TypeDescriptionReference *pTypeRef )
+{
+       // For simple types and small aggregates, size is rounded to 8
+       typelib_TypeDescription * pTypeDescr = 0;
+       TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
+       sal_uInt32 size = pTypeDescr->nSize;
+       TYPELIB_DANGER_RELEASE( pTypeDescr );
+       return ( size + 7 ) & ~7u;
+}
+
+} // namespace aarch64
diff --git a/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/abi.hxx 
b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/abi.hxx
new file mode 100644
index 0000000000..e6842af737
--- /dev/null
+++ b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/abi.hxx
@@ -0,0 +1,96 @@
+/*
+ * 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). It is a clean-room implementation written from that
+// public specification; 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;
+
+enum ReturnKind
+{
+       RETURN_KIND_HFA_FLOAT = 0x100,
+       RETURN_KIND_HFA_DOUBLE = 0x101
+};
+
+/* 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 );
+
+/** Return the assembly return kind for an HFA, or the type class otherwise. */
+sal_uInt32 get_return_kind( 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 );
+
+sal_uInt32 align_stack_offset(
+       sal_uInt32 offset, typelib_TypeDescriptionReference *pTypeRef );
+
+sal_uInt32 stack_size( typelib_TypeDescriptionReference *pTypeRef );
+
+} // namespace aarch64
+
+#endif // _BRIDGES_CPP_UNO_AARCH64_ABI_HXX_
diff --git a/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/call.s 
b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/call.s
new file mode 100644
index 0000000000..8eb2c6449e
--- /dev/null
+++ b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/call.s
@@ -0,0 +1,197 @@
+/*
+ * 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 (System V / FreeBSD) outgoing-call trampoline for the C++-UNO
+// bridge. Loads registers from caller-prepared arrays, copies overflow args
+// to the outgoing stack, performs the indirect call and stores return regs.
+
+       .text
+       .align 2
+       .globl callVirtualFunction
+       .type   callVirtualFunction, @function
+callVirtualFunction:
+       .cfi_startproc
+       // 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
+       .cfi_def_cfa x29, 64
+       .cfi_offset x29, -16
+       .cfi_offset x30, -8
+       .cfi_offset x19, -32
+       .cfi_offset x20, -24
+       .cfi_offset x21, -48
+       .cfi_offset x22, -40
+       .cfi_offset x23, -64
+       .cfi_offset x24, -56
+
+       // 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.
+       add     x9, x5, #15
+       bic     x9, x9, #15
+       sub     sp, sp, x9
+       mov     x10, #0
+Lcvf_copy:
+       cmp     x10, x5
+       b.ge    Lcvf_copied
+       ldrb    w11, [x4, x10]
+       strb    w11, [sp, x10]
+       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
+       .cfi_endproc
+
+// ---------------------------------------------------------------------------
+// privateSnippetExecutor: incoming (cpp2uno) register-spill executor.
+
+       .globl privateSnippetExecutor
+       .type   privateSnippetExecutor, @function
+privateSnippetExecutor:
+       .cfi_startproc
+       mov     x17, sp                 // x17 = ovrflw (incoming stack args)
+       stp     x29, x30, [sp, #-176]!
+       mov     x29, sp
+       .cfi_def_cfa x29, 176
+       .cfi_offset x29, -176
+       .cfi_offset x30, -168
+
+       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 (32-byte buffer)
+       bl      cpp_vtable_call
+
+       cmp     w0, #0x100                      // RETURN_KIND_HFA_FLOAT
+       b.eq    Lpse_hfa_float
+       cmp     w0, #0x101                      // RETURN_KIND_HFA_DOUBLE
+       b.eq    Lpse_hfa_double
+       cmp     w0, #10                 // typelib_TypeClass_FLOAT
+       b.eq    Lpse_float
+       cmp     w0, #11                 // typelib_TypeClass_DOUBLE
+       b.eq    Lpse_float
+       cmp     w0, #3                  // typelib_TypeClass_BYTE
+       b.eq    Lpse_signed_byte
+       cmp     w0, #4                  // typelib_TypeClass_SHORT
+       b.eq    Lpse_signed_short
+       cmp     w0, #1                  // typelib_TypeClass_VOID
+       b.eq    Lpse_void
+
+       // integer / pointer return
+       ldr     x0, [x6, #0]
+       ldr     x1, [x6, #8]
+       ldr     d0, [x6, #16]
+       ldr     d1, [x6, #24]
+       b       Lpse_finish
+
+Lpse_hfa_float:
+       // HFA float: up to 4 floats in d0..d3
+       ldr     d0, [x6, #0]
+       ldr     d1, [x6, #8]
+       ldr     d2, [x6, #16]
+       ldr     d3, [x6, #24]
+       b       Lpse_finish
+
+Lpse_hfa_double:
+       // HFA double: up to 4 doubles in d0..d3
+       ldr     d0, [x6, #0]
+       ldr     d1, [x6, #8]
+       ldr     d2, [x6, #16]
+       ldr     d3, [x6, #24]
+       b       Lpse_finish
+
+Lpse_float:
+       // single float/double returned in d0
+       ldr     d0, [x6, #16]
+       b       Lpse_finish
+
+Lpse_signed_byte:
+       ldr     x0, [x6, #0]
+       b       Lpse_finish
+
+Lpse_signed_short:
+       ldr     x0, [x6, #0]
+       b       Lpse_finish
+
+Lpse_void:
+       mov     x0, #0
+       b       Lpse_finish
+
+Lpse_finish:
+       ldp     x23, x24, [sp], #16
+       ldp     x21, x22, [sp], #16
+       ldp     x19, x20, [sp], #16
+       ldp     x29, x30, [sp], #16
+       ret
+       .cfi_endproc
+
+       .section        .note.GNU-stack,"",@progbits
diff --git a/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/cpp2uno.cxx 
b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/cpp2uno.cxx
new file mode 100644
index 0000000000..c6204dadf7
--- /dev/null
+++ b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/cpp2uno.cxx
@@ -0,0 +1,438 @@
+/*
+ * 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, unsigned char * 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
+       sal_uInt32 stackOffset = 0;
+
+       // 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;
+       // indices 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;
+               if ( !rParam.bOut && bridges::cpp_uno::shared::isSimpleType( 
rParam.pTypeRef ) ) // value
+               {
+                       // A simple UNO type occupies exactly one register, GPR 
or FPR.
+                       if ( rParam.pTypeRef->eTypeClass == 
typelib_TypeClass_FLOAT ||
+                                rParam.pTypeRef->eTypeClass == 
typelib_TypeClass_DOUBLE )
+                       {
+                               nUsedFPR = 1; nUsedGPR = 0;
+                       }
+                       else
+                       {
+                               nUsedFPR = 0; nUsedGPR = 1;
+                       }
+
+                       OSL_ASSERT( ( 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
+                               {
+                                       stackOffset = 
aarch64::align_stack_offset(
+                                               stackOffset, rParam.pTypeRef );
+                                       pCppArgs[nPos] = pUnoArgs[nPos] = 
ovrflw + stackOffset;
+                                       stackOffset += aarch64::stack_size( 
rParam.pTypeRef );
+                               }
+                       }
+                       else if ( nUsedGPR == 1 )
+                       {
+                               if ( nr_gpr < aarch64::MAX_GPR_REGS )
+                               {
+                                       pCppArgs[nPos] = pUnoArgs[nPos] = 
gpreg++;
+                                       nr_gpr++;
+                               }
+                               else
+                               {
+                                       stackOffset = 
aarch64::align_stack_offset(
+                                               stackOffset, rParam.pTypeRef );
+                                       pCppArgs[nPos] = pUnoArgs[nPos] = 
ovrflw + stackOffset;
+                                       stackOffset += aarch64::stack_size( 
rParam.pTypeRef );
+                               }
+                       }
+               }
+               else // struct <= 16 bytes || ptr to complex value || ref
+               {
+                       typelib_TypeDescription * pParamTypeDescr = 0;
+                       TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
+
+                       void *pCppStack = 0;
+                       if ( nr_gpr < aarch64::MAX_GPR_REGS )
+                       {
+                               pCppArgs[nPos] = pCppStack = *gpreg++;
+                               nr_gpr++;
+                       }
+                       else
+                       {
+                               stackOffset = (stackOffset + sizeof(void *) - 
1) &
+                                       ~(sizeof(void *) - 1);
+                               pCppArgs[nPos] = pCppStack =
+                                       *reinterpret_cast<void **>( ovrflw + 
stackOffset );
+                               stackOffset += sizeof(void *);
+                       }
+
+                       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;
+                       }
+
+                       if ( pCppStack )
+                       {
+                               if ( pParamTypeDescr->eTypeClass == 
typelib_TypeClass_STRUCT ||
+                                        pParamTypeDescr->eTypeClass == 
typelib_TypeClass_EXCEPTION )
+                               {
+                                       // struct in registers/stack: copy it 
to a temporary if
+                                       // it needs conversion
+                                       if ( 
bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ) )
+                                       {
+                                               // already handled above
+                                       }
+                                       else
+                                               pUnoArgs[nPos] = pCppStack;
+                               }
+                       }
+                       if ( pParamTypeDescr )
+                               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" sal_uInt32 cpp_vtable_call(
+       sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
+       void ** gpreg, void ** fpreg, unsigned char * 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] );
+
+       sal_uInt32 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 );
+                                       eRet = aarch64::get_return_kind( 
pAttrTypeRef );
+                       }
+                       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 );
+                                       eRet = aarch64::get_return_kind( 
pMethodTD->pReturnTypeRef );
+                               }
+                       }
+                       break;
+               }
+               default:
+               {
+                       throw RuntimeException( OUString::createFromAscii("no 
member description found!"),
+                                                                       
reinterpret_cast<XInterface *>( pCppI ) );
+                       // is here for dummy
+                       eRet = typelib_TypeClass_VOID;
+               }
+       }
+
+       return eRet;
+}
diff --git a/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/except.cxx 
b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/except.cxx
new file mode 100644
index 0000000000..e8caa2151c
--- /dev/null
+++ b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/except.cxx
@@ -0,0 +1,253 @@
+/*
+ * 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 <stdlib.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
+{
+
+namespace {
+
+typedef hash_map< void *, typelib_TypeDescription * > ThrownTypes;
+typedef hash_map< OUString, type_info *, OUStringHash > ObservedRttiMap;
+
+ThrownTypes & thrownTypes()
+{
+       static ThrownTypes types;
+       return types;
+}
+
+ObservedRttiMap & observedRttis()
+{
+       static ObservedRttiMap map;
+       return map;
+}
+
+// Guards BOTH thrownTypes() and observedRttis().  Every access to either map
+// must hold this one mutex; they are plain hash_maps, so an insertion racing a
+// find or erase is undefined behaviour.  RTTI::m_mutex may be held while
+// acquiring this one (see RTTI::getRTTI), never the other way round.
+Mutex & exceptionMapsMutex()
+{
+       static Mutex mutex;
+       return mutex;
+}
+
+// libc++ marks a type_info whose object is not unique across images by setting
+// the top bit of type_info::__type_name; comparison then falls back to strcmp
+// of the mangled name (see __non_unique_arm_rtti_bit_impl in <typeinfo>).  On
+// arm64 Darwin clang emits the typeinfo of every keyless class -- which is 
every
+// UNO exception -- hidden and therefore non-unique, so a synthesised object 
must
+// set the bit too, or std::type_info::operator== degenerates to an address
+// comparison and never matches the handler's real typeinfo.
+sal_uIntPtr const NON_UNIQUE_RTTI_BIT =
+       static_cast< sal_uIntPtr >(1) << (8 * sizeof (sal_uIntPtr) - 1);
+
+RttiSiClassLayout const * siDonor()
+{
+       return reinterpret_cast< RttiSiClassLayout const * >( 
&typeid(RttiDonorDerived) );
+}
+RttiClassLayout const * classDonor()
+{
+       return reinterpret_cast< RttiClassLayout const * >( 
&typeid(RttiDonorBase) );
+}
+
+// Refuse to synthesise unless the donors really have the layout we assume.
+bool rttiDonorsUsable()
+{
+       return sizeof (void *) == 8
+               && siDonor()->pBase == static_cast< void const * >( 
classDonor() );
+}
+
+// Mirror the platform's own convention rather than assuming it.
+bool rttiIsNonUnique()
+{
+       return (siDonor()->nName & NON_UNIQUE_RTTI_BIT) != 0;
+}
+
+}
+
+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
+}
+
+//==================================================================================================
+static OString mangledRttiSymbol( OUString const & unoName ) SAL_THROW( () )
+{
+       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' );
+       return buf.makeStringAndClear();
+}
+
+//==================================================================================================
+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;
+
+       type_info * synthesiseRTTI(
+               OString const & rSymbolName,
+               typelib_CompoundTypeDescription * pTypeDescr ) SAL_THROW( () );
+
+public:
+       RTTI() SAL_THROW( () );
+       ~RTTI() SAL_THROW( () );
+
+       type_info * getRTTI( typelib_CompoundTypeDescription * ) SAL_THROW( () 
);
+};
+
+//__________________________________________________________________________________________________
+RTTI::RTTI() SAL_THROW( () )
+{
+}
+
+//__________________________________________________________________________________________________
+RTTI::~RTTI() SAL_THROW( () )
+{
+}
+
+//__________________________________________________________________________________________________
+type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr ) 
SAL_THROW( () )
+{
+       OUString const & unoName = *(OUString const 
*)&pTypeDescr->aBase.pTypeName;
+
+       // Recursive: synthesiseRTTI() re-enters getRTTI() for the base chain.
+       // osl::Mutex is a PTHREAD_MUTEX_RECURSIVE (sal/osl/unx/mutex.c), so 
this
+       // is safe.  Lock order against exceptionMapsMutex() is unchanged.
+       MutexGuard guard( m_mutex );
+
+       {
+               MutexGuard observedGuard( exceptionMapsMutex() );
+               ObservedRttiMap::const_iterator observed( observedRttis().find( 
unoName ) );
+               if ( observed != observedRttis().end() )
+                       return observed->second;
+       }
+
+       t_rtti_map::const_iterator it = m_rttis.find( unoName );
+       if ( it != m_rttis.end() )
+               return it->second;
+
+       OString mangled = mangledRttiSymbol( unoName );
+
+       type_info * p = 0;
+       {
+               void * sym = dlsym( RTLD_DEFAULT, mangled.getStr() );
+               if ( sym )
+                       p = *reinterpret_cast< type_info ** >( sym );
+       }
+
+       if ( p )
+       {
+               m_rttis[ unoName ] = p;
+               return p;
+       }
+
+       // Fallback: synthesise a type_info object.
+       OString symName = mangled;
+       p = synthesiseRTTI( symName, pTypeDescr );
+       m_rttis[ unoName ] = p;
+       return p;
+}
+
+} // namespace CPPU_CURRENT_NAMESPACE
diff --git a/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/makefile.mk 
b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/makefile.mk
new file mode 100644
index 0000000000..e9b75c94fd
--- /dev/null
+++ b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/makefile.mk
@@ -0,0 +1,75 @@
+#**************************************************************
+#
+#  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 --------------------------------------------------------
+
+.IF "$(OS)-$(CPUNAME)-$(COMNAME)" == "FREEBSD-AARCH64-gcc3"
+
+.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
+
+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.
+$(SLO)$/%.obj: %.s
+       $(CXX) -c -o $(SLO)$/$(@:b).o $< -fPIC ; touch $@
diff --git a/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/share.hxx 
b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/share.hxx
new file mode 100644
index 0000000000..0b73a2a5fa
--- /dev/null
+++ b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/share.hxx
@@ -0,0 +1,65 @@
+/*
+ * 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 * );
+
+// Donor types for RTTI synthesis.  Their type_info objects are emitted by the
+// compiler, so they carry the real libc++abi vtables and the platform's own
+// uniqueness convention.  They must stay ordinary namespace-scope classes with
+// no virtual functions and a single public non-virtual base -- exactly the
+// shape of a generated UNO exception -- so that typeid(RttiDonorDerived) is a
+// __si_class_type_info and typeid(RttiDonorBase) a __class_type_info.
+// Do not move them into an anonymous namespace.
+struct RttiDonorBase { sal_Int32 dummy; };
+struct RttiDonorDerived : public RttiDonorBase { sal_Int32 dummy2; };
+
+// Itanium ABI object layouts 
(http://itanium-cxx-abi.github.io/cxx-abi/abi.html#rtti).
+// libc++abi does not publish __cxxabiv1::__class_type_info, and declaring a
+// look-alike class is not an option: it would get its own vtable, and
+// __class_type_info::can_catch() dynamic_casts the thrown type to the real
+// libc++abi class, so no typed handler would ever match.  We therefore build
+// raw storage in the ABI layout and install a borrowed, genuine vtable.
+struct RttiClassLayout   { void const * pVtable; sal_uIntPtr nName; };
+struct RttiSiClassLayout { void const * pVtable; sal_uIntPtr nName; void const 
* pBase; };
+
+extern "C" void *__cxa_allocate_exception(
+       std::size_t thrown_size ) throw();
+extern "C" void __cxa_free_exception( void *thrown_exception ) throw();
+extern "C" void __cxa_throw (
+       void *thrown_exception, std::type_info *tinfo, void (*dest) (void *) ) 
__attribute__((noreturn));
+extern "C" std::type_info *__cxa_current_exception_type();
+
+//==================================================================================================
+void raiseException(
+       uno_Any * pUnoExc, uno_Mapping * pUno2Cpp );
+//==================================================================================================
+void fillUnoException(
+       std::type_info const & type, void * exception, uno_Any *,
+       uno_Mapping * pCpp2Uno );
+}
diff --git a/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/uno2cpp.cxx 
b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/uno2cpp.cxx
new file mode 100644
index 0000000000..24e2627918
--- /dev/null
+++ b/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/uno2cpp.cxx
@@ -0,0 +1,189 @@
+/*
+ * 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,
+       unsigned char *pStack, sal_uInt32 nStackBytes,
+       sal_uInt64 *pGPRReturn, double *pFPRReturn );
+
+static void callVirtualMethod(void * pThis, sal_uInt32 nVtableIndex,
+                                                         void * 
pRegisterReturn, typelib_TypeDescriptionReference * pReturnTypeRef, bool 
bSimpleReturn,
+                                                         void * 
pIndirectReturn,
+                                                         unsigned char 
*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,
+                                                          unsigned char 
*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] );
+               // The overflow area is a packed byte image, not an array of 
words.
+               fprintf( stderr, "\nStack (%d bytes): ", nStack );
+               for ( unsigned int i = 0; i < nStack; ++i )
+                       fprintf( stderr, "%02x ", 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:
+               *reinterpret_cast<sal_Int32 *>( pRegisterReturn ) =
+                       *reinterpret_cast<sal_Int32 *>( &gpReturn[0] );
+               break;
+       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_UNSIGNED_SHORT:
+               *reinterpret_cast<sal_uInt16 *>( pRegisterReturn ) = 
*reinterpret_cast<sal_uInt16*>( &gpReturn[0] );
+               break;
+       case typelib_TypeClass_SHORT:
+               *reinterpret_cast<sal_Int16 *>( pRegisterReturn ) =
+                       *reinterpret_cast<sal_Int16 *>( &gpReturn[0] );
+               break;
+       case typelib_TypeClass_BOOLEAN:
+               *reinterpret_cast<sal_uInt8 *>( pRegisterReturn ) = 
*reinterpret_cast<sal_uInt8*>( &gpReturn[0] );
+               break;
+       case typelib_TypeClass_BYTE:
+               *reinterpret_cast<sal_Int8 *>( pRegisterReturn ) =
+                       *reinterpret_cast<sal_Int8 *>( &gpReturn[0] );
+               break;
+       case typelib_TypeClass_FLOAT:
+               *reinterpret_cast<float *>( pRegisterReturn ) =
+                       *reinterpret_cast<float *>( &fpReturn[0] );
+               break;
+       case typelib_TypeClass_DOUBLE:
+               *reinterpret_cast<double *>( pRegisterReturn ) =
+                       *reinterpret_cast<double *>( &fpReturn[0] );
+               break;
+       case typelib_TypeClass_STRUCT:
+       case typelib_TypeClass_EXCEPTION:
+               aarch64::fill_struct( pReturnTypeRef, gpReturn, fpReturn, 
pRegisterReturn );
+               break;
+       default:
+               break;
+       }
+}
+
+//==================================================================================================
+// The AArch64 outgoing-call trampoline, implemented in call.s, is declared in 
ABI
+// and used by callVirtualMethod above. The rest of the file implements the
+// public callVirtualMethod entrypoints used by the bridge; these are identical
+// to the macOS AArch64 implementation and therefore are compatible on FreeBSD.
+
+extern "C" void callVirtualFunction(
+       sal_uInt64 pFunction, sal_uInt64 pIndirectRet,
+       sal_uInt64 *pGPR, double *pFPR,
+       unsigned char *pStack, sal_uInt32 nStackBytes,
+       sal_uInt64 *pGPRReturn, double *pFPRReturn );
+
+// ... per-bridge wrappers are generated at build time; no further code 
required here.

Reply via email to