xref: /trunk/main/bridges/source/cpp_uno/gcc3_freebsd_aarch64/uno2cpp.cxx (revision 9c15e1abd703a7953928d7a80655ae1a76a41f6d)
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied.  See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 
21 // MARKER(update_precomp.py): autogen include statement, do not remove
22 #include "precompiled_bridges.hxx"
23 
24 #include <exception>
25 #include <typeinfo>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #include "rtl/alloc.h"
31 #include "rtl/ustrbuf.hxx"
32 
33 #include <com/sun/star/uno/genfunc.hxx>
34 #include "com/sun/star/uno/RuntimeException.hpp"
35 #include <uno/data.h>
36 
37 #include <bridges/cpp_uno/shared/bridge.hxx>
38 #include <bridges/cpp_uno/shared/types.hxx>
39 #include "bridges/cpp_uno/shared/unointerfaceproxy.hxx"
40 #include "bridges/cpp_uno/shared/vtables.hxx"
41 
42 #include "abi.hxx"
43 #include "share.hxx"
44 
45 using namespace ::rtl;
46 using namespace ::com::sun::star::uno;
47 
48 //==================================================================================================
49 
50 // The AArch64 outgoing-call trampoline, implemented in call.s.  It loads the
51 // argument registers from the caller-prepared arrays, copies overflow args to
52 // the outgoing stack, performs the indirect call, and returns x0/x1 and d0..d3.
53 extern "C" void callVirtualFunction(
54     sal_uInt64 pFunction, sal_uInt64 pIndirectRet,
55     sal_uInt64 *pGPR, double *pFPR,
56     unsigned char *pStack, sal_uInt32 nStackBytes,
57     sal_uInt64 *pGPRReturn, double *pFPRReturn );
58 
59 static void callVirtualMethod(void * pThis, sal_uInt32 nVtableIndex,
60                               void * pRegisterReturn, typelib_TypeDescriptionReference * pReturnTypeRef, bool bSimpleReturn,
61                               void * pIndirectReturn,
62                               unsigned char *pStack, sal_uInt32 nStack,
63                               sal_uInt64 *pGPR, sal_uInt32 nGPR,
64                               double *pFPR, sal_uInt32 nFPR) __attribute__((noinline));
65 
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)66 static void callVirtualMethod(void * pThis, sal_uInt32 nVtableIndex,
67                               void * pRegisterReturn, typelib_TypeDescriptionReference * pReturnTypeRef, bool bSimpleReturn,
68                               void * pIndirectReturn,
69                                unsigned char *pStack, sal_uInt32 nStack,
70                               sal_uInt64 *pGPR, sal_uInt32 nGPR,
71                               double *pFPR, sal_uInt32 nFPR)
72 {
73 #if OSL_DEBUG_LEVEL > 1
74     // Let's figure out what is really going on here
75     {
76         fprintf( stderr, "= callVirtualMethod() =\nGPR's (%d): ", nGPR );
77         for ( unsigned int i = 0; i < nGPR; ++i )
78             fprintf( stderr, "0x%lx, ", pGPR[i] );
79         fprintf( stderr, "\nFPR's (%d): ", nFPR );
80         for ( unsigned int i = 0; i < nFPR; ++i )
81             fprintf( stderr, "%f, ", pFPR[i] );
82         // The overflow area is a packed byte image, not an array of words.
83         fprintf( stderr, "\nStack (%d bytes): ", nStack );
84         for ( unsigned int i = 0; i < nStack; ++i )
85             fprintf( stderr, "%02x ", pStack[i] );
86         fprintf( stderr, "\n" );
87     }
88 #endif
89 
90     // The call instruction within callVirtualFunction may throw exceptions.  So
91     // that the compiler handles this correctly, it is important that (a)
92     // callVirtualMethod might call dummy_can_throw_anything (although this never
93     // happens at runtime), which in turn can throw exceptions, and (b)
94     // callVirtualMethod is not inlined at its call site (so that any exceptions
95     // thrown across the call are caught):
96     if ( !pThis )
97         CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything( "xxx" ); // address something
98 
99     // Should not happen, but...
100     if ( nFPR > aarch64::MAX_FPR_REGS )
101         nFPR = aarch64::MAX_FPR_REGS;
102     if ( nGPR > aarch64::MAX_GPR_REGS )
103         nGPR = aarch64::MAX_GPR_REGS;
104 
105     // Get pointer to the C++ virtual method from the vtable.
106     sal_uInt64 pMethod = *((sal_uInt64 *)pThis);
107     pMethod += 8 * nVtableIndex;
108     pMethod = *((sal_uInt64 *)pMethod);
109 
110     // Return register save areas: x0,x1 and d0..d3 (HFA up to 4 elements).
111     sal_uInt64 gpReturn[2] = { 0, 0 };
112     double fpReturn[4] = { 0, 0, 0, 0 };
113 
114     // Ensure the GPR/FPR arrays are the full register width even if fewer were
115     // filled (the trampoline always loads all 8 of each).
116     sal_uInt64 gpr[aarch64::MAX_GPR_REGS];
117     double fpr[aarch64::MAX_FPR_REGS];
118     for ( sal_uInt32 i = 0; i < aarch64::MAX_GPR_REGS; ++i )
119         gpr[i] = ( i < nGPR ) ? pGPR[i] : 0;
120     for ( sal_uInt32 i = 0; i < aarch64::MAX_FPR_REGS; ++i )
121         fpr[i] = ( i < nFPR ) ? pFPR[i] : 0;
122 
123     callVirtualFunction(
124         pMethod,
125         reinterpret_cast<sal_uInt64>( pIndirectReturn ), // x8, 0 if none
126         gpr, fpr,
127         pStack, nStack,
128         gpReturn, fpReturn );
129 
130     switch (pReturnTypeRef->eTypeClass)
131     {
132     case typelib_TypeClass_HYPER:
133     case typelib_TypeClass_UNSIGNED_HYPER:
134         *reinterpret_cast<sal_uInt64 *>( pRegisterReturn ) = gpReturn[0];
135         break;
136     case typelib_TypeClass_LONG:
137         *reinterpret_cast<sal_Int32 *>( pRegisterReturn ) =
138             *reinterpret_cast<sal_Int32 *>( &gpReturn[0] );
139         break;
140     case typelib_TypeClass_UNSIGNED_LONG:
141     case typelib_TypeClass_ENUM:
142         *reinterpret_cast<sal_uInt32 *>( pRegisterReturn ) =
143             *reinterpret_cast<sal_uInt32 *>( &gpReturn[0] );
144         break;
145     case typelib_TypeClass_CHAR:
146     case typelib_TypeClass_UNSIGNED_SHORT:
147         *reinterpret_cast<sal_uInt16 *>( pRegisterReturn ) = *reinterpret_cast<sal_uInt16*>( &gpReturn[0] );
148         break;
149     case typelib_TypeClass_SHORT:
150         *reinterpret_cast<sal_Int16 *>( pRegisterReturn ) =
151             *reinterpret_cast<sal_Int16 *>( &gpReturn[0] );
152         break;
153     case typelib_TypeClass_BOOLEAN:
154         *reinterpret_cast<sal_uInt8 *>( pRegisterReturn ) = *reinterpret_cast<sal_uInt8*>( &gpReturn[0] );
155         break;
156     case typelib_TypeClass_BYTE:
157         *reinterpret_cast<sal_Int8 *>( pRegisterReturn ) =
158             *reinterpret_cast<sal_Int8 *>( &gpReturn[0] );
159         break;
160     case typelib_TypeClass_FLOAT:
161         *reinterpret_cast<float *>( pRegisterReturn ) =
162             *reinterpret_cast<float *>( &fpReturn[0] );
163         break;
164     case typelib_TypeClass_DOUBLE:
165         *reinterpret_cast<double *>( pRegisterReturn ) =
166             *reinterpret_cast<double *>( &fpReturn[0] );
167         break;
168     case typelib_TypeClass_STRUCT:
169     case typelib_TypeClass_EXCEPTION:
170         aarch64::fill_struct( pReturnTypeRef, gpReturn, fpReturn, pRegisterReturn );
171         break;
172     default:
173         break;
174     }
175 }
176 
177 //==================================================================================================
178 // The AArch64 outgoing-call trampoline, implemented in call.s, is declared in ABI
179 // and used by callVirtualMethod above. The rest of the file implements the
180 // public callVirtualMethod entrypoints used by the bridge; these are identical
181 // to the macOS AArch64 implementation and therefore are compatible on FreeBSD.
182 
183 extern "C" void callVirtualFunction(
184     sal_uInt64 pFunction, sal_uInt64 pIndirectRet,
185     sal_uInt64 *pGPR, double *pFPR,
186     unsigned char *pStack, sal_uInt32 nStackBytes,
187     sal_uInt64 *pGPRReturn, double *pFPRReturn );
188 
189 // ... per-bridge wrappers are generated at build time; no further code required here.
190