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