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 <stdio.h>
25 #include <stdlib.h>
26 #include <hash_map>
27
28 #include <rtl/alloc.h>
29 #include <osl/mutex.hxx>
30
31 #include <com/sun/star/uno/genfunc.hxx>
32 #include "com/sun/star/uno/RuntimeException.hpp"
33 #include <uno/data.h>
34 #include <typelib/typedescription.hxx>
35
36 #include "bridges/cpp_uno/shared/bridge.hxx"
37 #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx"
38 #include "bridges/cpp_uno/shared/types.hxx"
39 #include "bridges/cpp_uno/shared/vtablefactory.hxx"
40
41 #include "abi.hxx"
42 #include "share.hxx"
43
44 using namespace ::osl;
45 using namespace ::rtl;
46 using namespace ::com::sun::star::uno;
47
48 //==================================================================================================
49
50 // Perform the UNO call
51 //
52 // We must convert the parameters stored in gpreg, fpreg and ovrflw to UNO
53 // arguments and call pThis->getUnoI()->pDispatcher.
54 //
55 // gpreg: this, [gpr params x0..x7] (the indirect-result ptr is x8, separate)
56 // fpreg: [fpr params d0..d7]
57 // ovrflw: [gpr or fpr params (properly aligned)]
58 //
59 // On AArch64 a structure bigger than 16 bytes is returned via the buffer
60 // addressed by x8 (pIndirectReturn); 'this' is always x0 = gpreg[0].
61 // Simple types are returned in x0,x1 (int) or d0,d1 (fp); HFAs in d0..d3;
62 // 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,unsigned char * ovrflw,void * pIndirectReturn,sal_uInt64 * pRegisterReturn)63 static typelib_TypeClass cpp2uno_call(
64 bridges::cpp_uno::shared::CppInterfaceProxy * pThis,
65 const typelib_TypeDescription * pMemberTypeDescr,
66 typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return
67 sal_Int32 nParams, typelib_MethodParameter * pParams,
68 void ** gpreg, void ** fpreg, unsigned char * ovrflw,
69 void * pIndirectReturn, // AArch64 x8 indirect-result pointer (0 if none)
70 sal_uInt64 * pRegisterReturn /* space for register return */ )
71 {
72 unsigned int nr_gpr = 0; //number of gpr registers used
73 unsigned int nr_fpr = 0; //number of fpr registers used
74 sal_uInt32 stackOffset = 0;
75
76 // return
77 typelib_TypeDescription * pReturnTypeDescr = 0;
78 if (pReturnTypeRef)
79 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
80
81 void * pUnoReturn = 0;
82 void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
83
84 if ( pReturnTypeDescr )
85 {
86 if ( aarch64::return_in_hidden_param( pReturnTypeRef ) )
87 {
88 // AArch64: the indirect-result pointer arrives in x8, NOT in the
89 // first general-purpose argument register (unlike x86-64 SysV).
90 // So we take it from pIndirectReturn and do NOT consume a gpreg
91 // slot here; 'this' still occupies gpreg[0] below.
92 pCppReturn = pIndirectReturn;
93
94 pUnoReturn = ( bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
95 ? alloca( pReturnTypeDescr->nSize )
96 : pCppReturn ); // direct way
97 }
98 else
99 pUnoReturn = pRegisterReturn; // direct way for simple types
100 }
101
102 // pop this (x0)
103 gpreg++;
104 nr_gpr++;
105
106 // stack space
107 // parameters
108 void ** pUnoArgs = reinterpret_cast<void **>(alloca( 4 * sizeof(void *) * nParams ));
109 void ** pCppArgs = pUnoArgs + nParams;
110 // indices of values this have to be converted (interface conversion cpp<=>uno)
111 sal_Int32 * pTempIndizes = reinterpret_cast<sal_Int32 *>(pUnoArgs + (2 * nParams));
112 // type descriptions for reconversions
113 typelib_TypeDescription ** ppTempParamTypeDescr = reinterpret_cast<typelib_TypeDescription **>(pUnoArgs + (3 * nParams));
114
115 sal_Int32 nTempIndizes = 0;
116
117 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
118 {
119 const typelib_MethodParameter & rParam = pParams[nPos];
120
121 int nUsedGPR = 0;
122 int nUsedFPR = 0;
123 if ( !rParam.bOut && bridges::cpp_uno::shared::isSimpleType( rParam.pTypeRef ) ) // value
124 {
125 // A simple UNO type occupies exactly one register, GPR or FPR.
126 if ( rParam.pTypeRef->eTypeClass == typelib_TypeClass_FLOAT ||
127 rParam.pTypeRef->eTypeClass == typelib_TypeClass_DOUBLE )
128 {
129 nUsedFPR = 1; nUsedGPR = 0;
130 }
131 else
132 {
133 nUsedFPR = 0; nUsedGPR = 1;
134 }
135
136 OSL_ASSERT( ( nUsedFPR == 1 && nUsedGPR == 0 ) || ( nUsedFPR == 0 && nUsedGPR == 1 ) );
137
138 if ( nUsedFPR == 1 )
139 {
140 if ( nr_fpr < aarch64::MAX_FPR_REGS )
141 {
142 pCppArgs[nPos] = pUnoArgs[nPos] = fpreg++;
143 nr_fpr++;
144 }
145 else
146 {
147 stackOffset = aarch64::align_stack_offset(
148 stackOffset, rParam.pTypeRef );
149 pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw + stackOffset;
150 stackOffset += aarch64::stack_size( rParam.pTypeRef );
151 }
152 }
153 else if ( nUsedGPR == 1 )
154 {
155 if ( nr_gpr < aarch64::MAX_GPR_REGS )
156 {
157 pCppArgs[nPos] = pUnoArgs[nPos] = gpreg++;
158 nr_gpr++;
159 }
160 else
161 {
162 stackOffset = aarch64::align_stack_offset(
163 stackOffset, rParam.pTypeRef );
164 pCppArgs[nPos] = pUnoArgs[nPos] = ovrflw + stackOffset;
165 stackOffset += aarch64::stack_size( rParam.pTypeRef );
166 }
167 }
168 }
169 else // struct <= 16 bytes || ptr to complex value || ref
170 {
171 typelib_TypeDescription * pParamTypeDescr = 0;
172 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
173
174 void *pCppStack = 0;
175 if ( nr_gpr < aarch64::MAX_GPR_REGS )
176 {
177 pCppArgs[nPos] = pCppStack = *gpreg++;
178 nr_gpr++;
179 }
180 else
181 {
182 stackOffset = (stackOffset + sizeof(void *) - 1) &
183 ~(sizeof(void *) - 1);
184 pCppArgs[nPos] = pCppStack =
185 *reinterpret_cast<void **>( ovrflw + stackOffset );
186 stackOffset += sizeof(void *);
187 }
188
189 if (! rParam.bIn) // is pure out
190 {
191 // uno out is unconstructed mem!
192 pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
193 pTempIndizes[nTempIndizes] = nPos;
194 // will be released at reconversion
195 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
196 }
197 else if ( bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ) ) // is in/inout
198 {
199 uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
200 pCppStack, pParamTypeDescr,
201 pThis->getBridge()->getCpp2Uno() );
202 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
203 // will be released at reconversion
204 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
205 }
206
207 if ( pCppStack )
208 {
209 if ( pParamTypeDescr->eTypeClass == typelib_TypeClass_STRUCT ||
210 pParamTypeDescr->eTypeClass == typelib_TypeClass_EXCEPTION )
211 {
212 // struct in registers/stack: copy it to a temporary if
213 // it needs conversion
214 if ( bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ) )
215 {
216 // already handled above
217 }
218 else
219 pUnoArgs[nPos] = pCppStack;
220 }
221 }
222 if ( pParamTypeDescr )
223 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
224 }
225 }
226
227 // ExceptionHolder
228 uno_Any aUnoExc; // Any will be constructed by callee
229 uno_Any * pUnoExc = &aUnoExc;
230
231 // invoke uno dispatch call
232 (*pThis->getUnoI()->pDispatcher)( pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
233
234 // in case an exception occurred...
235 if ( pUnoExc )
236 {
237 // destruct temporary in/inout params
238 for ( ; nTempIndizes--; )
239 {
240 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
241
242 if (pParams[nIndex].bIn) // is in/inout => was constructed
243 uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], 0 );
244 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
245 }
246 if (pReturnTypeDescr)
247 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
248
249 CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc, pThis->getBridge()->getUno2Cpp() ); // has to destruct the any
250 // is here for dummy
251 return typelib_TypeClass_VOID;
252 }
253 else // else no exception occurred...
254 {
255 // temporary params
256 for ( ; nTempIndizes--; )
257 {
258 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
259 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
260
261 if ( pParams[nIndex].bOut ) // inout/out
262 {
263 // convert and assign
264 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
265 uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
266 pThis->getBridge()->getUno2Cpp() );
267 }
268 // destroy temp uno param
269 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
270
271 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
272 }
273 // return
274 if ( pCppReturn ) // has complex return
275 {
276 if ( pUnoReturn != pCppReturn ) // needs reconversion
277 {
278 uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
279 pThis->getBridge()->getUno2Cpp() );
280 // destroy temp uno return
281 uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
282 }
283 // complex return ptr is set to return reg
284 *reinterpret_cast<void **>(pRegisterReturn) = pCppReturn;
285 }
286 if ( pReturnTypeDescr )
287 {
288 typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
289 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
290 return eRet;
291 }
292 else
293 return typelib_TypeClass_VOID;
294 }
295 }
296
297
298 //==================================================================================================
cpp_vtable_call(sal_Int32 nFunctionIndex,sal_Int32 nVtableOffset,void ** gpreg,void ** fpreg,unsigned char * ovrflw,void * pIndirectReturn,sal_uInt64 * pRegisterReturn)299 extern "C" sal_uInt32 cpp_vtable_call(
300 sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
301 void ** gpreg, void ** fpreg, unsigned char * ovrflw,
302 void * pIndirectReturn, // AArch64 x8 indirect-result pointer (0 if none)
303 sal_uInt64 * pRegisterReturn /* space for register return */ )
304 {
305 // gpreg: this, [other gpr params x0..x7]
306 // fpreg: [fpr params d0..d7]
307 // ovrflw: [gpr or fpr params (properly aligned)]
308 // pIndirectReturn: x8 (the hidden return buffer), when bit 0x80000000 set.
309 //
310 // On AArch64 'this' is ALWAYS x0 = gpreg[0]; the hidden return pointer is
311 // the separate x8 register, not a displaced first GPR (unlike x86-64 SysV
312 // where it occupied gpreg[0] and 'this' moved to gpreg[1]).
313 if ( nFunctionIndex & 0x80000000 )
314 nFunctionIndex &= 0x7fffffff;
315
316 void * pThis = gpreg[0];
317 pThis = static_cast<char *>( pThis ) - nVtableOffset;
318
319 bridges::cpp_uno::shared::CppInterfaceProxy * pCppI =
320 bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy( pThis );
321
322 typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
323
324 OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!\n" );
325 if ( nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex )
326 {
327 throw RuntimeException( OUString::createFromAscii("illegal vtable index!"),
328 reinterpret_cast<XInterface *>( pCppI ) );
329 }
330
331 // determine called method
332 sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
333 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!\n" );
334
335 TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
336
337 sal_uInt32 eRet;
338 switch ( aMemberDescr.get()->eTypeClass )
339 {
340 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
341 {
342 typelib_TypeDescriptionReference *pAttrTypeRef =
343 reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( aMemberDescr.get() )->pAttributeTypeRef;
344
345 if ( pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex )
346 {
347 // is GET method
348 eRet = cpp2uno_call( pCppI, aMemberDescr.get(), pAttrTypeRef,
349 0, 0, // no params
350 gpreg, fpreg, ovrflw, pIndirectReturn, pRegisterReturn );
351 eRet = aarch64::get_return_kind( pAttrTypeRef );
352 }
353 else
354 {
355 // is SET method
356 typelib_MethodParameter aParam;
357 aParam.pTypeRef = pAttrTypeRef;
358 aParam.bIn = sal_True;
359 aParam.bOut = sal_False;
360
361 eRet = cpp2uno_call( pCppI, aMemberDescr.get(),
362 0, // indicates void return
363 1, &aParam,
364 gpreg, fpreg, ovrflw, pIndirectReturn, pRegisterReturn );
365 }
366 break;
367 }
368 case typelib_TypeClass_INTERFACE_METHOD:
369 {
370 // is METHOD
371 switch ( nFunctionIndex )
372 {
373 case 1: // acquire()
374 pCppI->acquireProxy(); // non virtual call!
375 eRet = typelib_TypeClass_VOID;
376 break;
377 case 2: // release()
378 pCppI->releaseProxy(); // non virtual call!
379 eRet = typelib_TypeClass_VOID;
380 break;
381 case 0: // queryInterface() opt
382 {
383 // queryInterface([in] type) returns an Any (> 16 bytes),
384 // so on AArch64 the result buffer is x8 (pIndirectReturn),
385 // 'this' is gpreg[0], and the type argument is the first
386 // real parameter, gpreg[1].
387 typelib_TypeDescription * pTD = 0;
388 TYPELIB_DANGER_GET( &pTD, reinterpret_cast<Type *>( gpreg[1] )->getTypeLibType() );
389 if ( pTD )
390 {
391 XInterface * pInterface = 0;
392 (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)
393 ( pCppI->getBridge()->getCppEnv(),
394 reinterpret_cast<void **>(&pInterface),
395 pCppI->getOid().pData,
396 reinterpret_cast<typelib_InterfaceTypeDescription *>( pTD ) );
397
398 if ( pInterface )
399 {
400 ::uno_any_construct( reinterpret_cast<uno_Any *>( pIndirectReturn ),
401 &pInterface, pTD, cpp_acquire );
402
403 pInterface->release();
404 TYPELIB_DANGER_RELEASE( pTD );
405
406 reinterpret_cast<void **>( pRegisterReturn )[0] = pIndirectReturn;
407 eRet = typelib_TypeClass_ANY;
408 break;
409 }
410 TYPELIB_DANGER_RELEASE( pTD );
411 }
412 } // else perform queryInterface()
413 default:
414 {
415 typelib_InterfaceMethodTypeDescription *pMethodTD =
416 reinterpret_cast<typelib_InterfaceMethodTypeDescription *>( aMemberDescr.get() );
417
418 eRet = cpp2uno_call( pCppI, aMemberDescr.get(),
419 pMethodTD->pReturnTypeRef,
420 pMethodTD->nParams,
421 pMethodTD->pParams,
422 gpreg, fpreg, ovrflw, pIndirectReturn, pRegisterReturn );
423 eRet = aarch64::get_return_kind( pMethodTD->pReturnTypeRef );
424 }
425 }
426 break;
427 }
428 default:
429 {
430 throw RuntimeException( OUString::createFromAscii("no member description found!"),
431 reinterpret_cast<XInterface *>( pCppI ) );
432 // is here for dummy
433 eRet = typelib_TypeClass_VOID;
434 }
435 }
436
437 return eRet;
438 }
439