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