xref: /AOO42X/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/cpp2uno.cxx (revision cd15cd7435a5992ecd53f36ec66392bf63f53df1)
1*cd15cd74SJim Jagielski /**************************************************************
2*cd15cd74SJim Jagielski  *
3*cd15cd74SJim Jagielski  * Licensed to the Apache Software Foundation (ASF) under one
4*cd15cd74SJim Jagielski  * or more contributor license agreements.  See the NOTICE file
5*cd15cd74SJim Jagielski  * distributed with this work for additional information
6*cd15cd74SJim Jagielski  * regarding copyright ownership.  The ASF licenses this file
7*cd15cd74SJim Jagielski  * to you under the Apache License, Version 2.0 (the
8*cd15cd74SJim Jagielski  * "License"); you may not use this file except in compliance
9*cd15cd74SJim Jagielski  * with the License.  You may obtain a copy of the License at
10*cd15cd74SJim Jagielski  *
11*cd15cd74SJim Jagielski  *   http://www.apache.org/licenses/LICENSE-2.0
12*cd15cd74SJim Jagielski  *
13*cd15cd74SJim Jagielski  * Unless required by applicable law or agreed to in writing,
14*cd15cd74SJim Jagielski  * software distributed under the License is distributed on an
15*cd15cd74SJim Jagielski  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*cd15cd74SJim Jagielski  * KIND, either express or implied.  See the License for the
17*cd15cd74SJim Jagielski  * specific language governing permissions and limitations
18*cd15cd74SJim Jagielski  * under the License.
19*cd15cd74SJim Jagielski  *
20*cd15cd74SJim Jagielski  *************************************************************/
21*cd15cd74SJim Jagielski 
22*cd15cd74SJim Jagielski 
23*cd15cd74SJim Jagielski 
24*cd15cd74SJim Jagielski // MARKER(update_precomp.py): autogen include statement, do not remove
25*cd15cd74SJim Jagielski #include "precompiled_bridges.hxx"
26*cd15cd74SJim Jagielski 
27*cd15cd74SJim Jagielski #include <stdio.h>
28*cd15cd74SJim Jagielski #include <stdlib.h>
29*cd15cd74SJim Jagielski #include <hash_map>
30*cd15cd74SJim Jagielski 
31*cd15cd74SJim Jagielski #include <rtl/alloc.h>
32*cd15cd74SJim Jagielski #include <osl/mutex.hxx>
33*cd15cd74SJim Jagielski 
34*cd15cd74SJim Jagielski #include <com/sun/star/uno/genfunc.hxx>
35*cd15cd74SJim Jagielski #include "com/sun/star/uno/RuntimeException.hpp"
36*cd15cd74SJim Jagielski #include <uno/data.h>
37*cd15cd74SJim Jagielski #include <typelib/typedescription.hxx>
38*cd15cd74SJim Jagielski 
39*cd15cd74SJim Jagielski #include "bridges/cpp_uno/shared/bridge.hxx"
40*cd15cd74SJim Jagielski #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx"
41*cd15cd74SJim Jagielski #include "bridges/cpp_uno/shared/types.hxx"
42*cd15cd74SJim Jagielski #include "bridges/cpp_uno/shared/vtablefactory.hxx"
43*cd15cd74SJim Jagielski 
44*cd15cd74SJim Jagielski #include "abi.hxx"
45*cd15cd74SJim Jagielski #include "share.hxx"
46*cd15cd74SJim Jagielski 
47*cd15cd74SJim Jagielski using namespace ::osl;
48*cd15cd74SJim Jagielski using namespace ::rtl;
49*cd15cd74SJim Jagielski using namespace ::com::sun::star::uno;
50*cd15cd74SJim Jagielski 
51*cd15cd74SJim Jagielski //==================================================================================================
52*cd15cd74SJim Jagielski 
53*cd15cd74SJim Jagielski // Perform the UNO call
54*cd15cd74SJim Jagielski //
55*cd15cd74SJim Jagielski // We must convert the parameters stored in gpreg, fpreg and ovrflw to UNO
56*cd15cd74SJim Jagielski // arguments and call pThis->getUnoI()->pDispatcher.
57*cd15cd74SJim Jagielski //
58*cd15cd74SJim Jagielski // gpreg:  this, [gpr params x0..x7]   (the indirect-result ptr is x8, separate)
59*cd15cd74SJim Jagielski // fpreg:  [fpr params d0..d7]
60*cd15cd74SJim Jagielski // ovrflw: [gpr or fpr params (properly aligned)]
61*cd15cd74SJim Jagielski //
62*cd15cd74SJim Jagielski // On AArch64 a structure bigger than 16 bytes is returned via the buffer
63*cd15cd74SJim Jagielski // addressed by x8 (pIndirectReturn); 'this' is always x0 = gpreg[0].
64*cd15cd74SJim Jagielski // Simple types are returned in x0,x1 (int) or d0,d1 (fp); HFAs in d0..d3;
65*cd15cd74SJim Jagielski // non-HFA structures <= 16 bytes in x0,x1.
cpp2uno_call(bridges::cpp_uno::shared::CppInterfaceProxy * pThis,const typelib_TypeDescription * pMemberTypeDescr,typelib_TypeDescriptionReference * pReturnTypeRef,sal_Int32 nParams,typelib_MethodParameter * pParams,void ** gpreg,void ** fpreg,void ** ovrflw,void * pIndirectReturn,sal_uInt64 * pRegisterReturn)66*cd15cd74SJim Jagielski static typelib_TypeClass cpp2uno_call(
67*cd15cd74SJim Jagielski     bridges::cpp_uno::shared::CppInterfaceProxy * pThis,
68*cd15cd74SJim Jagielski     const typelib_TypeDescription * pMemberTypeDescr,
69*cd15cd74SJim Jagielski     typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return
70*cd15cd74SJim Jagielski     sal_Int32 nParams, typelib_MethodParameter * pParams,
71*cd15cd74SJim Jagielski     void ** gpreg, void ** fpreg, void ** ovrflw,
72*cd15cd74SJim Jagielski     void * pIndirectReturn, // AArch64 x8 indirect-result pointer (0 if none)
73*cd15cd74SJim Jagielski     sal_uInt64 * pRegisterReturn /* space for register return */ )
74*cd15cd74SJim Jagielski {
75*cd15cd74SJim Jagielski     unsigned int nr_gpr = 0; //number of gpr registers used
76*cd15cd74SJim Jagielski     unsigned int nr_fpr = 0; //number of fpr registers used
77*cd15cd74SJim Jagielski 
78*cd15cd74SJim Jagielski     // return
79*cd15cd74SJim Jagielski     typelib_TypeDescription * pReturnTypeDescr = 0;
80*cd15cd74SJim Jagielski     if (pReturnTypeRef)
81*cd15cd74SJim Jagielski         TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
82*cd15cd74SJim Jagielski 
83*cd15cd74SJim Jagielski     void * pUnoReturn = 0;
84*cd15cd74SJim Jagielski     void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
85*cd15cd74SJim Jagielski 
86*cd15cd74SJim Jagielski     if ( pReturnTypeDescr )
87*cd15cd74SJim Jagielski     {
88*cd15cd74SJim Jagielski         if ( aarch64::return_in_hidden_param( pReturnTypeRef ) )
89*cd15cd74SJim Jagielski         {
90*cd15cd74SJim Jagielski             // AArch64: the indirect-result pointer arrives in x8, NOT in the
91*cd15cd74SJim Jagielski             // first general-purpose argument register (unlike x86-64 SysV).
92*cd15cd74SJim Jagielski             // So we take it from pIndirectReturn and do NOT consume a gpreg
93*cd15cd74SJim Jagielski             // slot here; 'this' still occupies gpreg[0] below.
94*cd15cd74SJim Jagielski             pCppReturn = pIndirectReturn;
95*cd15cd74SJim Jagielski 
96*cd15cd74SJim Jagielski             pUnoReturn = ( bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
97*cd15cd74SJim Jagielski                            ? alloca( pReturnTypeDescr->nSize )
98*cd15cd74SJim Jagielski                            : pCppReturn ); // direct way
99*cd15cd74SJim Jagielski         }
100*cd15cd74SJim Jagielski         else
101*cd15cd74SJim Jagielski             pUnoReturn = pRegisterReturn; // direct way for simple types
102*cd15cd74SJim Jagielski     }
103*cd15cd74SJim Jagielski 
104*cd15cd74SJim Jagielski     // pop this (x0)
105*cd15cd74SJim Jagielski     gpreg++;
106*cd15cd74SJim Jagielski     nr_gpr++;
107*cd15cd74SJim Jagielski 
108*cd15cd74SJim Jagielski     // stack space
109*cd15cd74SJim Jagielski     // parameters
110*cd15cd74SJim Jagielski     void ** pUnoArgs = reinterpret_cast<void **>(alloca( 4 * sizeof(void *) * nParams ));
111*cd15cd74SJim Jagielski     void ** pCppArgs = pUnoArgs + nParams;
112*cd15cd74SJim Jagielski     // indizes of values this have to be converted (interface conversion cpp<=>uno)
113*cd15cd74SJim Jagielski     sal_Int32 * pTempIndizes = reinterpret_cast<sal_Int32 *>(pUnoArgs + (2 * nParams));
114*cd15cd74SJim Jagielski     // type descriptions for reconversions
115*cd15cd74SJim Jagielski     typelib_TypeDescription ** ppTempParamTypeDescr = reinterpret_cast<typelib_TypeDescription **>(pUnoArgs + (3 * nParams));
116*cd15cd74SJim Jagielski 
117*cd15cd74SJim Jagielski     sal_Int32 nTempIndizes = 0;
118*cd15cd74SJim Jagielski 
119*cd15cd74SJim Jagielski     for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
120*cd15cd74SJim Jagielski     {
121*cd15cd74SJim Jagielski         const typelib_MethodParameter & rParam = pParams[nPos];
122*cd15cd74SJim Jagielski 
123*cd15cd74SJim Jagielski         int nUsedGPR = 0;
124*cd15cd74SJim Jagielski         int nUsedFPR = 0;
125*cd15cd74SJim Jagielski         bool bFitsRegisters = aarch64::examine_argument( rParam.pTypeRef, false, nUsedGPR, nUsedFPR );
126*cd15cd74SJim Jagielski         if ( !rParam.bOut && bridges::cpp_uno::shared::isSimpleType( rParam.pTypeRef ) ) // value
127*cd15cd74SJim Jagielski         {
128*cd15cd74SJim Jagielski             // A simple UNO type occupies exactly one register, GPR or FPR.
129*cd15cd74SJim Jagielski             OSL_ASSERT( bFitsRegisters && ( ( nUsedFPR == 1 && nUsedGPR == 0 ) || ( nUsedFPR == 0 && nUsedGPR == 1 ) ) );
130*cd15cd74SJim Jagielski 
131*cd15cd74SJim Jagielski             if ( nUsedFPR == 1 )
132*cd15cd74SJim Jagielski             {
133*cd15cd74SJim Jagielski                 if ( nr_fpr < aarch64::MAX_FPR_REGS )
134*cd15cd74SJim Jagielski                 {
135*cd15cd74SJim Jagielski                     pCppArgs[nPos] = pUnoArgs[nPos] = fpreg++;
136*cd15cd74SJim Jagielski                     nr_fpr++;
137*cd15cd74SJim Jagielski                 }
138*cd15cd74SJim Jagielski                 else
139*cd15cd74SJim Jagielski                     pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw++;
140*cd15cd74SJim Jagielski             }
141*cd15cd74SJim Jagielski             else if ( nUsedGPR == 1 )
142*cd15cd74SJim Jagielski             {
143*cd15cd74SJim Jagielski                 if ( nr_gpr < aarch64::MAX_GPR_REGS )
144*cd15cd74SJim Jagielski                 {
145*cd15cd74SJim Jagielski                     pCppArgs[nPos] = pUnoArgs[nPos] = gpreg++;
146*cd15cd74SJim Jagielski                     nr_gpr++;
147*cd15cd74SJim Jagielski                 }
148*cd15cd74SJim Jagielski                 else
149*cd15cd74SJim Jagielski                     pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw++;
150*cd15cd74SJim Jagielski             }
151*cd15cd74SJim Jagielski         }
152*cd15cd74SJim Jagielski         else // struct <= 16 bytes || ptr to complex value || ref
153*cd15cd74SJim Jagielski         {
154*cd15cd74SJim Jagielski             typelib_TypeDescription * pParamTypeDescr = 0;
155*cd15cd74SJim Jagielski             TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
156*cd15cd74SJim Jagielski 
157*cd15cd74SJim Jagielski             void *pCppStack;
158*cd15cd74SJim Jagielski             if ( nr_gpr < aarch64::MAX_GPR_REGS )
159*cd15cd74SJim Jagielski             {
160*cd15cd74SJim Jagielski                 pCppArgs[nPos] = pCppStack = *gpreg++;
161*cd15cd74SJim Jagielski                 nr_gpr++;
162*cd15cd74SJim Jagielski             }
163*cd15cd74SJim Jagielski             else
164*cd15cd74SJim Jagielski                 pCppArgs[nPos] = pCppStack = *ovrflw++;
165*cd15cd74SJim Jagielski 
166*cd15cd74SJim Jagielski             if (! rParam.bIn) // is pure out
167*cd15cd74SJim Jagielski             {
168*cd15cd74SJim Jagielski                 // uno out is unconstructed mem!
169*cd15cd74SJim Jagielski                 pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
170*cd15cd74SJim Jagielski                 pTempIndizes[nTempIndizes] = nPos;
171*cd15cd74SJim Jagielski                 // will be released at reconversion
172*cd15cd74SJim Jagielski                 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
173*cd15cd74SJim Jagielski             }
174*cd15cd74SJim Jagielski             else if ( bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ) ) // is in/inout
175*cd15cd74SJim Jagielski             {
176*cd15cd74SJim Jagielski                 uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
177*cd15cd74SJim Jagielski                                         pCppStack, pParamTypeDescr,
178*cd15cd74SJim Jagielski                                         pThis->getBridge()->getCpp2Uno() );
179*cd15cd74SJim Jagielski                 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
180*cd15cd74SJim Jagielski                 // will be released at reconversion
181*cd15cd74SJim Jagielski                 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
182*cd15cd74SJim Jagielski             }
183*cd15cd74SJim Jagielski             else // direct way
184*cd15cd74SJim Jagielski             {
185*cd15cd74SJim Jagielski                 pUnoArgs[nPos] = pCppStack;
186*cd15cd74SJim Jagielski                 // no longer needed
187*cd15cd74SJim Jagielski                 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
188*cd15cd74SJim Jagielski             }
189*cd15cd74SJim Jagielski         }
190*cd15cd74SJim Jagielski     }
191*cd15cd74SJim Jagielski 
192*cd15cd74SJim Jagielski     // ExceptionHolder
193*cd15cd74SJim Jagielski     uno_Any aUnoExc; // Any will be constructed by callee
194*cd15cd74SJim Jagielski     uno_Any * pUnoExc = &aUnoExc;
195*cd15cd74SJim Jagielski 
196*cd15cd74SJim Jagielski     // invoke uno dispatch call
197*cd15cd74SJim Jagielski     (*pThis->getUnoI()->pDispatcher)( pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
198*cd15cd74SJim Jagielski 
199*cd15cd74SJim Jagielski     // in case an exception occurred...
200*cd15cd74SJim Jagielski     if ( pUnoExc )
201*cd15cd74SJim Jagielski     {
202*cd15cd74SJim Jagielski         // destruct temporary in/inout params
203*cd15cd74SJim Jagielski         for ( ; nTempIndizes--; )
204*cd15cd74SJim Jagielski         {
205*cd15cd74SJim Jagielski             sal_Int32 nIndex = pTempIndizes[nTempIndizes];
206*cd15cd74SJim Jagielski 
207*cd15cd74SJim Jagielski             if (pParams[nIndex].bIn) // is in/inout => was constructed
208*cd15cd74SJim Jagielski                 uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], 0 );
209*cd15cd74SJim Jagielski             TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
210*cd15cd74SJim Jagielski         }
211*cd15cd74SJim Jagielski         if (pReturnTypeDescr)
212*cd15cd74SJim Jagielski             TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
213*cd15cd74SJim Jagielski 
214*cd15cd74SJim Jagielski         CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc, pThis->getBridge()->getUno2Cpp() ); // has to destruct the any
215*cd15cd74SJim Jagielski         // is here for dummy
216*cd15cd74SJim Jagielski         return typelib_TypeClass_VOID;
217*cd15cd74SJim Jagielski     }
218*cd15cd74SJim Jagielski     else // else no exception occurred...
219*cd15cd74SJim Jagielski     {
220*cd15cd74SJim Jagielski         // temporary params
221*cd15cd74SJim Jagielski         for ( ; nTempIndizes--; )
222*cd15cd74SJim Jagielski         {
223*cd15cd74SJim Jagielski             sal_Int32 nIndex = pTempIndizes[nTempIndizes];
224*cd15cd74SJim Jagielski             typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
225*cd15cd74SJim Jagielski 
226*cd15cd74SJim Jagielski             if ( pParams[nIndex].bOut ) // inout/out
227*cd15cd74SJim Jagielski             {
228*cd15cd74SJim Jagielski                 // convert and assign
229*cd15cd74SJim Jagielski                 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
230*cd15cd74SJim Jagielski                 uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
231*cd15cd74SJim Jagielski                                         pThis->getBridge()->getUno2Cpp() );
232*cd15cd74SJim Jagielski             }
233*cd15cd74SJim Jagielski             // destroy temp uno param
234*cd15cd74SJim Jagielski             uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
235*cd15cd74SJim Jagielski 
236*cd15cd74SJim Jagielski             TYPELIB_DANGER_RELEASE( pParamTypeDescr );
237*cd15cd74SJim Jagielski         }
238*cd15cd74SJim Jagielski         // return
239*cd15cd74SJim Jagielski         if ( pCppReturn ) // has complex return
240*cd15cd74SJim Jagielski         {
241*cd15cd74SJim Jagielski             if ( pUnoReturn != pCppReturn ) // needs reconversion
242*cd15cd74SJim Jagielski             {
243*cd15cd74SJim Jagielski                 uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
244*cd15cd74SJim Jagielski                                         pThis->getBridge()->getUno2Cpp() );
245*cd15cd74SJim Jagielski                 // destroy temp uno return
246*cd15cd74SJim Jagielski                 uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
247*cd15cd74SJim Jagielski             }
248*cd15cd74SJim Jagielski             // complex return ptr is set to return reg
249*cd15cd74SJim Jagielski             *reinterpret_cast<void **>(pRegisterReturn) = pCppReturn;
250*cd15cd74SJim Jagielski         }
251*cd15cd74SJim Jagielski         if ( pReturnTypeDescr )
252*cd15cd74SJim Jagielski         {
253*cd15cd74SJim Jagielski             typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
254*cd15cd74SJim Jagielski             TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
255*cd15cd74SJim Jagielski             return eRet;
256*cd15cd74SJim Jagielski         }
257*cd15cd74SJim Jagielski         else
258*cd15cd74SJim Jagielski             return typelib_TypeClass_VOID;
259*cd15cd74SJim Jagielski     }
260*cd15cd74SJim Jagielski }
261*cd15cd74SJim Jagielski 
262*cd15cd74SJim Jagielski 
263*cd15cd74SJim Jagielski //==================================================================================================
cpp_vtable_call(sal_Int32 nFunctionIndex,sal_Int32 nVtableOffset,void ** gpreg,void ** fpreg,void ** ovrflw,void * pIndirectReturn,sal_uInt64 * pRegisterReturn)264*cd15cd74SJim Jagielski extern "C" typelib_TypeClass cpp_vtable_call(
265*cd15cd74SJim Jagielski     sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
266*cd15cd74SJim Jagielski     void ** gpreg, void ** fpreg, void ** ovrflw,
267*cd15cd74SJim Jagielski     void * pIndirectReturn, // AArch64 x8 indirect-result pointer (0 if none)
268*cd15cd74SJim Jagielski     sal_uInt64 * pRegisterReturn /* space for register return */ )
269*cd15cd74SJim Jagielski {
270*cd15cd74SJim Jagielski     // gpreg:  this, [other gpr params x0..x7]
271*cd15cd74SJim Jagielski     // fpreg:  [fpr params d0..d7]
272*cd15cd74SJim Jagielski     // ovrflw: [gpr or fpr params (properly aligned)]
273*cd15cd74SJim Jagielski     // pIndirectReturn: x8 (the hidden return buffer), when bit 0x80000000 set.
274*cd15cd74SJim Jagielski     //
275*cd15cd74SJim Jagielski     // On AArch64 'this' is ALWAYS x0 = gpreg[0]; the hidden return pointer is
276*cd15cd74SJim Jagielski     // the separate x8 register, not a displaced first GPR (unlike x86-64 SysV
277*cd15cd74SJim Jagielski     // where it occupied gpreg[0] and 'this' moved to gpreg[1]).
278*cd15cd74SJim Jagielski     if ( nFunctionIndex & 0x80000000 )
279*cd15cd74SJim Jagielski         nFunctionIndex &= 0x7fffffff;
280*cd15cd74SJim Jagielski 
281*cd15cd74SJim Jagielski     void * pThis = gpreg[0];
282*cd15cd74SJim Jagielski     pThis = static_cast<char *>( pThis ) - nVtableOffset;
283*cd15cd74SJim Jagielski 
284*cd15cd74SJim Jagielski     bridges::cpp_uno::shared::CppInterfaceProxy * pCppI =
285*cd15cd74SJim Jagielski         bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( pThis );
286*cd15cd74SJim Jagielski 
287*cd15cd74SJim Jagielski     typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
288*cd15cd74SJim Jagielski 
289*cd15cd74SJim Jagielski     OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!\n" );
290*cd15cd74SJim Jagielski     if ( nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex )
291*cd15cd74SJim Jagielski     {
292*cd15cd74SJim Jagielski         throw RuntimeException( OUString::createFromAscii("illegal vtable index!"),
293*cd15cd74SJim Jagielski                                 reinterpret_cast<XInterface *>( pCppI ) );
294*cd15cd74SJim Jagielski     }
295*cd15cd74SJim Jagielski 
296*cd15cd74SJim Jagielski     // determine called method
297*cd15cd74SJim Jagielski     sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
298*cd15cd74SJim Jagielski     OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!\n" );
299*cd15cd74SJim Jagielski 
300*cd15cd74SJim Jagielski     TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
301*cd15cd74SJim Jagielski 
302*cd15cd74SJim Jagielski     typelib_TypeClass eRet;
303*cd15cd74SJim Jagielski     switch ( aMemberDescr.get()->eTypeClass )
304*cd15cd74SJim Jagielski     {
305*cd15cd74SJim Jagielski         case typelib_TypeClass_INTERFACE_ATTRIBUTE:
306*cd15cd74SJim Jagielski         {
307*cd15cd74SJim Jagielski             typelib_TypeDescriptionReference *pAttrTypeRef =
308*cd15cd74SJim Jagielski                 reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( aMemberDescr.get() )->pAttributeTypeRef;
309*cd15cd74SJim Jagielski 
310*cd15cd74SJim Jagielski             if ( pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex )
311*cd15cd74SJim Jagielski             {
312*cd15cd74SJim Jagielski                 // is GET method
313*cd15cd74SJim Jagielski                 eRet = cpp2uno_call( pCppI, aMemberDescr.get(), pAttrTypeRef,
314*cd15cd74SJim Jagielski                         0, 0, // no params
315*cd15cd74SJim Jagielski                         gpreg, fpreg, ovrflw, pIndirectReturn, pRegisterReturn );
316*cd15cd74SJim Jagielski             }
317*cd15cd74SJim Jagielski             else
318*cd15cd74SJim Jagielski             {
319*cd15cd74SJim Jagielski                 // is SET method
320*cd15cd74SJim Jagielski                 typelib_MethodParameter aParam;
321*cd15cd74SJim Jagielski                 aParam.pTypeRef = pAttrTypeRef;
322*cd15cd74SJim Jagielski                 aParam.bIn      = sal_True;
323*cd15cd74SJim Jagielski                 aParam.bOut     = sal_False;
324*cd15cd74SJim Jagielski 
325*cd15cd74SJim Jagielski                 eRet = cpp2uno_call( pCppI, aMemberDescr.get(),
326*cd15cd74SJim Jagielski                         0, // indicates void return
327*cd15cd74SJim Jagielski                         1, &aParam,
328*cd15cd74SJim Jagielski                         gpreg, fpreg, ovrflw, pIndirectReturn, pRegisterReturn );
329*cd15cd74SJim Jagielski             }
330*cd15cd74SJim Jagielski             break;
331*cd15cd74SJim Jagielski         }
332*cd15cd74SJim Jagielski         case typelib_TypeClass_INTERFACE_METHOD:
333*cd15cd74SJim Jagielski         {
334*cd15cd74SJim Jagielski             // is METHOD
335*cd15cd74SJim Jagielski             switch ( nFunctionIndex )
336*cd15cd74SJim Jagielski             {
337*cd15cd74SJim Jagielski                 case 1: // acquire()
338*cd15cd74SJim Jagielski                     pCppI->acquireProxy(); // non virtual call!
339*cd15cd74SJim Jagielski                     eRet = typelib_TypeClass_VOID;
340*cd15cd74SJim Jagielski                     break;
341*cd15cd74SJim Jagielski                 case 2: // release()
342*cd15cd74SJim Jagielski                     pCppI->releaseProxy(); // non virtual call!
343*cd15cd74SJim Jagielski                     eRet = typelib_TypeClass_VOID;
344*cd15cd74SJim Jagielski                     break;
345*cd15cd74SJim Jagielski                 case 0: // queryInterface() opt
346*cd15cd74SJim Jagielski                 {
347*cd15cd74SJim Jagielski                     // queryInterface([in] type) returns an Any (> 16 bytes),
348*cd15cd74SJim Jagielski                     // so on AArch64 the result buffer is x8 (pIndirectReturn),
349*cd15cd74SJim Jagielski                     // 'this' is gpreg[0], and the type argument is the first
350*cd15cd74SJim Jagielski                     // real parameter, gpreg[1].
351*cd15cd74SJim Jagielski                     typelib_TypeDescription * pTD = 0;
352*cd15cd74SJim Jagielski                     TYPELIB_DANGER_GET( &pTD, reinterpret_cast<Type *>( gpreg[1] )->getTypeLibType() );
353*cd15cd74SJim Jagielski                     if ( pTD )
354*cd15cd74SJim Jagielski                     {
355*cd15cd74SJim Jagielski                         XInterface * pInterface = 0;
356*cd15cd74SJim Jagielski                         (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)
357*cd15cd74SJim Jagielski                             ( pCppI->getBridge()->getCppEnv(),
358*cd15cd74SJim Jagielski                               reinterpret_cast<void **>(&pInterface),
359*cd15cd74SJim Jagielski                               pCppI->getOid().pData,
360*cd15cd74SJim Jagielski                               reinterpret_cast<typelib_InterfaceTypeDescription *>( pTD ) );
361*cd15cd74SJim Jagielski 
362*cd15cd74SJim Jagielski                         if ( pInterface )
363*cd15cd74SJim Jagielski                         {
364*cd15cd74SJim Jagielski                             ::uno_any_construct( reinterpret_cast<uno_Any *>( pIndirectReturn ),
365*cd15cd74SJim Jagielski                                                  &pInterface, pTD, cpp_acquire );
366*cd15cd74SJim Jagielski 
367*cd15cd74SJim Jagielski                             pInterface->release();
368*cd15cd74SJim Jagielski                             TYPELIB_DANGER_RELEASE( pTD );
369*cd15cd74SJim Jagielski 
370*cd15cd74SJim Jagielski                             reinterpret_cast<void **>( pRegisterReturn )[0] = pIndirectReturn;
371*cd15cd74SJim Jagielski                             eRet = typelib_TypeClass_ANY;
372*cd15cd74SJim Jagielski                             break;
373*cd15cd74SJim Jagielski                         }
374*cd15cd74SJim Jagielski                         TYPELIB_DANGER_RELEASE( pTD );
375*cd15cd74SJim Jagielski                     }
376*cd15cd74SJim Jagielski                 } // else perform queryInterface()
377*cd15cd74SJim Jagielski                 default:
378*cd15cd74SJim Jagielski                 {
379*cd15cd74SJim Jagielski                     typelib_InterfaceMethodTypeDescription *pMethodTD =
380*cd15cd74SJim Jagielski                         reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( aMemberDescr.get() );
381*cd15cd74SJim Jagielski 
382*cd15cd74SJim Jagielski                     eRet = cpp2uno_call( pCppI, aMemberDescr.get(),
383*cd15cd74SJim Jagielski                                          pMethodTD->pReturnTypeRef,
384*cd15cd74SJim Jagielski                                          pMethodTD->nParams,
385*cd15cd74SJim Jagielski                                          pMethodTD->pParams,
386*cd15cd74SJim Jagielski                                          gpreg, fpreg, ovrflw, pIndirectReturn, pRegisterReturn );
387*cd15cd74SJim Jagielski                 }
388*cd15cd74SJim Jagielski             }
389*cd15cd74SJim Jagielski             break;
390*cd15cd74SJim Jagielski         }
391*cd15cd74SJim Jagielski         default:
392*cd15cd74SJim Jagielski         {
393*cd15cd74SJim Jagielski             throw RuntimeException( OUString::createFromAscii("no member description found!"),
394*cd15cd74SJim Jagielski                                     reinterpret_cast<XInterface *>( pCppI ) );
395*cd15cd74SJim Jagielski             // is here for dummy
396*cd15cd74SJim Jagielski             eRet = typelib_TypeClass_VOID;
397*cd15cd74SJim Jagielski         }
398*cd15cd74SJim Jagielski     }
399*cd15cd74SJim Jagielski 
400*cd15cd74SJim Jagielski     return eRet;
401*cd15cd74SJim Jagielski }
402*cd15cd74SJim Jagielski 
403*cd15cd74SJim Jagielski //==================================================================================================
404*cd15cd74SJim Jagielski // The incoming register-spill executor, implemented in call.s.  It is reached
405*cd15cd74SJim Jagielski // via BR from a per-slot snippet (codeSnippet below) with x16 carrying the
406*cd15cd74SJim Jagielski // packed (nVtableOffset << 32) | nFunctionIndex; it spills the argument
407*cd15cd74SJim Jagielski // registers and calls cpp_vtable_call.
408*cd15cd74SJim Jagielski extern "C" void privateSnippetExecutor( void );
409*cd15cd74SJim Jagielski 
410*cd15cd74SJim Jagielski // Each snippet is 5 AArch64 instructions (20 bytes) + 4 bytes padding to an
411*cd15cd74SJim Jagielski // 8-byte boundary + two 8-byte literals (the packed index and the executor
412*cd15cd74SJim Jagielski // address) = 40 bytes.
413*cd15cd74SJim Jagielski const int codeSnippetSize = 40;
414*cd15cd74SJim Jagielski 
415*cd15cd74SJim Jagielski // Generate a per-vtable-slot trampoline that loads the packed function index
416*cd15cd74SJim Jagielski // into x16 and branches to privateSnippetExecutor(), preserving every
417*cd15cd74SJim Jagielski // argument register.  Uses PC-relative literal loads because AArch64 cannot
418*cd15cd74SJim Jagielski // embed a 64-bit immediate in a single instruction.
419*cd15cd74SJim Jagielski //
420*cd15cd74SJim Jagielski // Layout (offsets in bytes from code):
421*cd15cd74SJim Jagielski //    0:  ldr  x16, #24      ; x16 = nOffsetAndIndex (literal at +24)
422*cd15cd74SJim Jagielski //    4:  ldr  x17, #28      ; x17 = privateSnippetExecutor (literal at +32)
423*cd15cd74SJim Jagielski //    8:  br   x17
424*cd15cd74SJim Jagielski //   12:  (unused / padding)
425*cd15cd74SJim Jagielski //   16:  (padding to 8-byte align the literals at 24)
426*cd15cd74SJim Jagielski //   24:  .quad nOffsetAndIndex
427*cd15cd74SJim Jagielski //   32:  .quad privateSnippetExecutor
428*cd15cd74SJim Jagielski //
429*cd15cd74SJim Jagielski // Note: the snippet creates no stack frame, so the C++ unwinder walks straight
430*cd15cd74SJim Jagielski // through it to the original caller (required for UNO exception propagation).
codeSnippet(unsigned char * code,sal_Int32 nFunctionIndex,sal_Int32 nVtableOffset,bool bHasHiddenParam)431*cd15cd74SJim Jagielski unsigned char * codeSnippet( unsigned char * code,
432*cd15cd74SJim Jagielski         sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
433*cd15cd74SJim Jagielski         bool bHasHiddenParam ) SAL_THROW( () )
434*cd15cd74SJim Jagielski {
435*cd15cd74SJim Jagielski     sal_uInt64 nOffsetAndIndex = ( static_cast<sal_uInt64>( nVtableOffset ) << 32 ) | static_cast<sal_uInt64>( nFunctionIndex );
436*cd15cd74SJim Jagielski 
437*cd15cd74SJim Jagielski     if ( bHasHiddenParam )
438*cd15cd74SJim Jagielski         nOffsetAndIndex |= 0x80000000;
439*cd15cd74SJim Jagielski 
440*cd15cd74SJim Jagielski     sal_uInt32 * p = reinterpret_cast<sal_uInt32 *>( code );
441*cd15cd74SJim Jagielski 
442*cd15cd74SJim Jagielski     // ldr x16, #24  -> literal at code+24. imm19 = 24/4 = 6.
443*cd15cd74SJim Jagielski     //   encoding: 0x58000000 | (imm19 << 5) | Rt(16)
444*cd15cd74SJim Jagielski     p[0] = 0x58000000 | ( 6 << 5 ) | 16;
445*cd15cd74SJim Jagielski     // ldr x17, #28  -> literal at code+32 (relative to this insn at +4): 28.
446*cd15cd74SJim Jagielski     //   imm19 = 28/4 = 7.
447*cd15cd74SJim Jagielski     p[1] = 0x58000000 | ( 7 << 5 ) | 17;
448*cd15cd74SJim Jagielski     // br x17  -> 0xD61F0000 | (Rn(17) << 5)
449*cd15cd74SJim Jagielski     p[2] = 0xD61F0000 | ( 17 << 5 );
450*cd15cd74SJim Jagielski     // p[3] (offset 12) and p[4] (offset 16..20) are padding.
451*cd15cd74SJim Jagielski     p[3] = 0xD503201F; // NOP
452*cd15cd74SJim Jagielski     p[4] = 0xD503201F; // NOP
453*cd15cd74SJim Jagielski 
454*cd15cd74SJim Jagielski     // literals, 8-byte aligned at offset 24 and 32
455*cd15cd74SJim Jagielski     *reinterpret_cast<sal_uInt64 *>( code + 24 ) = nOffsetAndIndex;
456*cd15cd74SJim Jagielski     *reinterpret_cast<sal_uInt64 *>( code + 32 ) = reinterpret_cast<sal_uInt64>( privateSnippetExecutor );
457*cd15cd74SJim Jagielski 
458*cd15cd74SJim Jagielski     return code + codeSnippetSize;
459*cd15cd74SJim Jagielski }
460*cd15cd74SJim Jagielski 
461*cd15cd74SJim Jagielski //==================================================================================================
462*cd15cd74SJim Jagielski struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; };
463*cd15cd74SJim Jagielski 
464*cd15cd74SJim Jagielski bridges::cpp_uno::shared::VtableFactory::Slot *
mapBlockToVtable(void * block)465*cd15cd74SJim Jagielski bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
466*cd15cd74SJim Jagielski {
467*cd15cd74SJim Jagielski     return static_cast< Slot * >(block) + 2;
468*cd15cd74SJim Jagielski }
469*cd15cd74SJim Jagielski 
470*cd15cd74SJim Jagielski //==================================================================================================
getBlockSize(sal_Int32 slotCount)471*cd15cd74SJim Jagielski sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize(
472*cd15cd74SJim Jagielski     sal_Int32 slotCount)
473*cd15cd74SJim Jagielski {
474*cd15cd74SJim Jagielski     return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
475*cd15cd74SJim Jagielski }
476*cd15cd74SJim Jagielski 
477*cd15cd74SJim Jagielski //==================================================================================================
478*cd15cd74SJim Jagielski bridges::cpp_uno::shared::VtableFactory::Slot *
initializeBlock(void * block,sal_Int32 slotCount)479*cd15cd74SJim Jagielski bridges::cpp_uno::shared::VtableFactory::initializeBlock(
480*cd15cd74SJim Jagielski     void * block, sal_Int32 slotCount)
481*cd15cd74SJim Jagielski {
482*cd15cd74SJim Jagielski     Slot * slots = mapBlockToVtable(block);
483*cd15cd74SJim Jagielski     slots[-2].fn = 0;
484*cd15cd74SJim Jagielski     slots[-1].fn = 0;
485*cd15cd74SJim Jagielski     return slots + slotCount;
486*cd15cd74SJim Jagielski }
487*cd15cd74SJim Jagielski 
488*cd15cd74SJim Jagielski //==================================================================================================
489*cd15cd74SJim Jagielski 
addLocalFunctions(Slot ** slots,unsigned char * code,typelib_InterfaceTypeDescription const * type,sal_Int32 nFunctionOffset,sal_Int32 functionCount,sal_Int32 nVtableOffset)490*cd15cd74SJim Jagielski unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
491*cd15cd74SJim Jagielski     Slot ** slots, unsigned char * code, /*sal_PtrDiff writetoexecdiff,*/
492*cd15cd74SJim Jagielski     typelib_InterfaceTypeDescription const * type, sal_Int32 nFunctionOffset,
493*cd15cd74SJim Jagielski     sal_Int32 functionCount, sal_Int32 nVtableOffset )
494*cd15cd74SJim Jagielski {
495*cd15cd74SJim Jagielski     const sal_PtrDiff writetoexecdiff = 0;
496*cd15cd74SJim Jagielski     (*slots) -= functionCount;
497*cd15cd74SJim Jagielski     Slot * s = *slots;
498*cd15cd74SJim Jagielski     for ( sal_Int32 nPos = 0; nPos < type->nMembers; ++nPos )
499*cd15cd74SJim Jagielski     {
500*cd15cd74SJim Jagielski         typelib_TypeDescription * pTD = 0;
501*cd15cd74SJim Jagielski 
502*cd15cd74SJim Jagielski         TYPELIB_DANGER_GET( &pTD, type->ppMembers[ nPos ] );
503*cd15cd74SJim Jagielski         OSL_ASSERT( pTD );
504*cd15cd74SJim Jagielski 
505*cd15cd74SJim Jagielski         if ( typelib_TypeClass_INTERFACE_ATTRIBUTE == pTD->eTypeClass )
506*cd15cd74SJim Jagielski         {
507*cd15cd74SJim Jagielski             typelib_InterfaceAttributeTypeDescription *pAttrTD =
508*cd15cd74SJim Jagielski                 reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( pTD );
509*cd15cd74SJim Jagielski 
510*cd15cd74SJim Jagielski             // get method
511*cd15cd74SJim Jagielski             (s++)->fn = code + writetoexecdiff;
512*cd15cd74SJim Jagielski             code = codeSnippet( code, nFunctionOffset++, nVtableOffset,
513*cd15cd74SJim Jagielski                                 aarch64::return_in_hidden_param( pAttrTD->pAttributeTypeRef ) );
514*cd15cd74SJim Jagielski 
515*cd15cd74SJim Jagielski             if ( ! pAttrTD->bReadOnly )
516*cd15cd74SJim Jagielski             {
517*cd15cd74SJim Jagielski                 // set method
518*cd15cd74SJim Jagielski                 (s++)->fn = code + writetoexecdiff;
519*cd15cd74SJim Jagielski                 code = codeSnippet( code, nFunctionOffset++, nVtableOffset, false );
520*cd15cd74SJim Jagielski             }
521*cd15cd74SJim Jagielski         }
522*cd15cd74SJim Jagielski         else if ( typelib_TypeClass_INTERFACE_METHOD == pTD->eTypeClass )
523*cd15cd74SJim Jagielski         {
524*cd15cd74SJim Jagielski             typelib_InterfaceMethodTypeDescription *pMethodTD =
525*cd15cd74SJim Jagielski                 reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( pTD );
526*cd15cd74SJim Jagielski 
527*cd15cd74SJim Jagielski             (s++)->fn = code + writetoexecdiff;
528*cd15cd74SJim Jagielski             code = codeSnippet( code, nFunctionOffset++, nVtableOffset,
529*cd15cd74SJim Jagielski                                 aarch64::return_in_hidden_param( pMethodTD->pReturnTypeRef ) );
530*cd15cd74SJim Jagielski         }
531*cd15cd74SJim Jagielski         else
532*cd15cd74SJim Jagielski             OSL_ASSERT( false );
533*cd15cd74SJim Jagielski 
534*cd15cd74SJim Jagielski         TYPELIB_DANGER_RELEASE( pTD );
535*cd15cd74SJim Jagielski     }
536*cd15cd74SJim Jagielski     return code;
537*cd15cd74SJim Jagielski }
538*cd15cd74SJim Jagielski 
539*cd15cd74SJim Jagielski //==================================================================================================
flushCode(unsigned char const *,unsigned char const *)540*cd15cd74SJim Jagielski void bridges::cpp_uno::shared::VtableFactory::flushCode(
541*cd15cd74SJim Jagielski     unsigned char const *, unsigned char const * )
542*cd15cd74SJim Jagielski {
543*cd15cd74SJim Jagielski }
544