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