bump product version to 6.3.0.0.beta1
[LibreOffice.git] / bridges / source / cpp_uno / gcc3_linux_mips64 / uno2cpp.cxx
blobabb43c1fea8ab53b5928302a47b7673800f2ab1d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <exception>
23 #include <malloc.h>
24 #include <cstring>
25 #include <typeinfo>
27 #include <com/sun/star/uno/Exception.hpp>
28 #include <com/sun/star/uno/RuntimeException.hpp>
29 #include <com/sun/star/uno/genfunc.hxx>
30 #include <o3tl/runtimetooustring.hxx>
31 #include <uno/data.h>
33 #include "bridge.hxx"
34 #include "types.hxx"
35 #include "unointerfaceproxy.hxx"
36 #include "vtables.hxx"
38 #include "share.hxx"
40 //#define BRDEBUG
41 #ifdef BRDEBUG
42 #include <stdio.h>
43 #endif
45 #define INSERT_FLOAT_DOUBLE( pSV, nr, pFPR, pDS ) \
46 if ( nr < MAX_FP_REGS ) \
47 pFPR[nr++] = *reinterpret_cast<double *>( pSV ); \
48 else \
49 *pDS++ = *reinterpret_cast<sal_uInt64 *>( pSV ); // verbatim!
51 #define INSERT_INT64( pSV, nr, pGPR, pDS ) \
52 if ( nr < MAX_GP_REGS ) \
53 pGPR[nr++] = *reinterpret_cast<sal_Int64 *>( pSV ); \
54 else \
55 *pDS++ = *reinterpret_cast<sal_Int64 *>( pSV );
57 #define INSERT_INT32( pSV, nr, pGPR, pDS ) \
58 if ( nr < MAX_GP_REGS ) \
59 pGPR[nr++] = *reinterpret_cast<sal_Int32 *>( pSV ); \
60 else \
61 *pDS++ = *reinterpret_cast<sal_Int32 *>( pSV );
63 #define INSERT_INT16( pSV, nr, pGPR, pDS ) \
64 if ( nr < MAX_GP_REGS ) \
65 pGPR[nr++] = *reinterpret_cast<sal_Int16 *>( pSV ); \
66 else \
67 *pDS++ = *reinterpret_cast<sal_Int16 *>( pSV );
69 #define INSERT_UINT16( pSV, nr, pGPR, pDS ) \
70 if ( nr < MAX_GP_REGS ) \
71 pGPR[nr++] = *reinterpret_cast<sal_uInt16 *>( pSV ); \
72 else \
73 *pDS++ = *reinterpret_cast<sal_uInt16 *>( pSV );
75 #define INSERT_INT8( pSV, nr, pGPR, pDS ) \
76 if ( nr < MAX_GP_REGS ) \
77 pGPR[nr++] = *reinterpret_cast<sal_Int8 *>( pSV ); \
78 else \
79 *pDS++ = *reinterpret_cast<sal_Int8 *>( pSV );
81 using namespace ::com::sun::star::uno;
83 namespace
86 bool isReturnInFPR(const typelib_TypeDescription * pTypeDescr, sal_uInt32 & nSize)
88 const typelib_CompoundTypeDescription *p =
89 reinterpret_cast<const typelib_CompoundTypeDescription*>( pTypeDescr );
91 for (sal_Int32 i = 0; i < p->nMembers; ++i)
93 typelib_TypeDescriptionReference *pTypeInStruct = p->ppTypeRefs[ i ];
95 switch (pTypeInStruct->eTypeClass)
97 case typelib_TypeClass_STRUCT:
98 case typelib_TypeClass_EXCEPTION:
100 typelib_TypeDescription * t = 0;
101 TYPELIB_DANGER_GET(&t, pTypeInStruct);
102 bool isFPR = isReturnInFPR(t, nSize);
103 TYPELIB_DANGER_RELEASE(t);
104 if (!isFPR)
105 return false;
107 break;
108 case typelib_TypeClass_FLOAT:
109 case typelib_TypeClass_DOUBLE:
110 if (nSize >= 16)
111 return false;
112 nSize += 8;
113 break;
114 default:
115 return false;
116 break;
119 return true;
122 void fillReturn(const typelib_TypeDescription * pTypeDescr,
123 sal_Int64 * gret, double * fret, void * pRegisterReturn)
125 sal_uInt32 nSize = 0;
126 if (isReturnInFPR(pTypeDescr, nSize))
128 reinterpret_cast<double *>( pRegisterReturn )[0] = fret[0];
129 reinterpret_cast<double *>( pRegisterReturn )[1] = fret[1];
131 else
133 reinterpret_cast<sal_Int64 *>( pRegisterReturn )[0] = gret[0];
134 reinterpret_cast<sal_Int64 *>( pRegisterReturn )[1] = gret[1];
138 static void callVirtualMethod(
139 void * pAdjustedThisPtr,
140 sal_Int32 nVtableIndex,
141 void * pRegisterReturn,
142 typelib_TypeDescriptionReference * pReturnTypeRef,
143 bool bSimpleReturn,
144 sal_uInt64 *pStack,
145 sal_uInt32 nStack,
146 sal_uInt64 *pGPR,
147 double *pFPR,
148 sal_uInt32 nREG)
150 // Should not happen, but...
151 static_assert(MAX_GP_REGS == MAX_FP_REGS, "must be the same size");
152 if ( nREG > MAX_GP_REGS )
153 nREG = MAX_GP_REGS;
155 // Get pointer to method
156 sal_uInt64 pMethod = *((sal_uInt64 *)pAdjustedThisPtr);
157 pMethod += 8 * nVtableIndex;
158 void *mfunc = (void *) *((sal_uInt64 *)pMethod);
159 #ifdef BRDEBUG
160 fprintf(stderr, "calling function %p\n", mfunc);
161 #endif
163 // Load parameters to stack, if necessary
164 sal_uInt64* pCallStack = NULL;
165 if ( nStack )
167 // 16-bytes aligned
168 sal_uInt32 nStackBytes = ( ( nStack + 1 ) >> 1 ) * 16;
169 pCallStack = (sal_uInt64 *) __builtin_alloca( nStackBytes );
170 std::memcpy( pCallStack, pStack, nStackBytes );
173 sal_Int64 gret[2];
174 double fret[2];
175 asm volatile (
176 ".set push \n\t"
177 ".set mips64 \n\t"
178 // Fill the general purpose registers
179 "ld $4, 0(%[gpr]) \n\t"
180 "ld $5, 8(%[gpr]) \n\t"
181 "ld $6, 16(%[gpr]) \n\t"
182 "ld $7, 24(%[gpr]) \n\t"
183 "ld $8, 32(%[gpr]) \n\t"
184 "ld $9, 40(%[gpr]) \n\t"
185 "ld $10, 48(%[gpr]) \n\t"
186 "ld $11, 56(%[gpr]) \n\t"
187 // Fill the floating pointer registers
188 "ldc1 $f12, 0(%[fpr]) \n\t"
189 "ldc1 $f13, 8(%[fpr]) \n\t"
190 "ldc1 $f14, 16(%[fpr]) \n\t"
191 "ldc1 $f15, 24(%[fpr]) \n\t"
192 "ldc1 $f16, 32(%[fpr]) \n\t"
193 "ldc1 $f17, 40(%[fpr]) \n\t"
194 "ldc1 $f18, 48(%[fpr]) \n\t"
195 "ldc1 $f19, 56(%[fpr]) \n\t"
196 // Perform the call
197 "jalr %[mfunc] \n\t"
198 // Fill the return values
199 "move %[gret1], $2 \n\t"
200 "move %[gret2], $3 \n\t"
201 "mov.d %[fret1], $f0 \n\t"
202 "mov.d %[fret2], $f2 \n\t"
203 ".set pop \n\t"
204 :[gret1]"=r"(gret[0]), [gret2]"=r"(gret[1]),
205 [fret1]"=f"(fret[0]), [fret2]"=f"(fret[1])
206 :[gpr]"r"(pGPR), [fpr]"r"(pFPR), [mfunc]"c"(mfunc),
207 [stack]"m"(pCallStack) // dummy input to prevent the compiler from optimizing the alloca out
208 :"$2", "$3", "$4", "$5", "$6", "$7", "$8",
209 "$9", "$10", "$11", "$31",
210 "$f0", "$f2", "$f12", "$f13", "$f14", "$f15",
211 "$f16", "$f17", "$f18", "$f19", "memory"
214 switch (pReturnTypeRef->eTypeClass)
216 case typelib_TypeClass_HYPER:
217 case typelib_TypeClass_UNSIGNED_HYPER:
218 case typelib_TypeClass_LONG:
219 case typelib_TypeClass_UNSIGNED_LONG:
220 case typelib_TypeClass_ENUM:
221 case typelib_TypeClass_CHAR:
222 case typelib_TypeClass_SHORT:
223 case typelib_TypeClass_UNSIGNED_SHORT:
224 case typelib_TypeClass_BOOLEAN:
225 case typelib_TypeClass_BYTE:
226 *reinterpret_cast<sal_Int64 *>( pRegisterReturn ) = gret[0];
227 break;
228 case typelib_TypeClass_FLOAT:
229 case typelib_TypeClass_DOUBLE:
230 *reinterpret_cast<double *>( pRegisterReturn ) = fret[0];
231 break;
232 case typelib_TypeClass_STRUCT:
233 case typelib_TypeClass_EXCEPTION:
235 sal_Int32 const nRetSize = pReturnTypeRef->pType->nSize;
236 if (bSimpleReturn && nRetSize <= 16 && nRetSize > 0)
238 typelib_TypeDescription * pTypeDescr = 0;
239 TYPELIB_DANGER_GET( &pTypeDescr, pReturnTypeRef );
240 fillReturn(pTypeDescr, gret, fret, pRegisterReturn);
241 TYPELIB_DANGER_RELEASE( pTypeDescr );
243 break;
245 default:
246 #ifdef BRDEBUG
247 fprintf(stderr,"unhandled return type %u\n", pReturnTypeRef->eTypeClass);
248 #endif
249 break;
254 static void cpp_call(
255 bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
256 bridges::cpp_uno::shared::VtableSlot aVtableSlot,
257 typelib_TypeDescriptionReference * pReturnTypeRef,
258 sal_Int32 nParams, typelib_MethodParameter * pParams,
259 void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
261 // max space for: [complex ret ptr], values|ptr ...
262 sal_uInt64 *pStack = (sal_uInt64 *)__builtin_alloca( ((nParams+3) * sizeof(sal_Int64)) );
263 sal_uInt64 *pStackStart = pStack;
265 sal_uInt64 pGPR[MAX_GP_REGS];
266 double pFPR[MAX_FP_REGS];
267 sal_uInt32 nREG = 0;
269 #ifdef BRDEBUG
270 fprintf(stderr, "in cpp_call\n");
271 #endif
273 // return
274 typelib_TypeDescription * pReturnTypeDescr = 0;
275 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
276 assert(pReturnTypeDescr);
278 void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
280 bool bSimpleReturn = true;
281 if (pReturnTypeDescr)
283 if ( CPPU_CURRENT_NAMESPACE::return_in_hidden_param( pReturnTypeRef ) )
285 bSimpleReturn = false;
286 // complex return via ptr
287 pCppReturn = bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )?
288 __builtin_alloca( pReturnTypeDescr->nSize ) : pUnoReturn;
289 INSERT_INT64( &pCppReturn, nREG, pGPR, pStack );
291 else
293 pCppReturn = pUnoReturn; // direct way for simple types
297 // push this
298 void* pAdjustedThisPtr = reinterpret_cast< void **>( pThis->getCppI() ) + aVtableSlot.offset;
299 INSERT_INT64( &pAdjustedThisPtr, nREG, pGPR, pStack );
301 // args
302 void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams );
303 // indices of values this have to be converted (interface conversion cpp<=>uno)
304 sal_Int32 * pTempIndices = (sal_Int32 *)(pCppArgs + nParams);
305 // type descriptions for reconversions
306 typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
308 sal_Int32 nTempIndices = 0;
310 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
312 const typelib_MethodParameter & rParam = pParams[nPos];
313 typelib_TypeDescription * pParamTypeDescr = 0;
314 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
316 if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
318 uno_copyAndConvertData( pCppArgs[nPos] = alloca( 8 ), pUnoArgs[nPos], pParamTypeDescr,
319 pThis->getBridge()->getUno2Cpp() );
321 switch (pParamTypeDescr->eTypeClass)
323 case typelib_TypeClass_LONG:
324 case typelib_TypeClass_UNSIGNED_LONG:
325 case typelib_TypeClass_ENUM:
326 INSERT_INT32( pCppArgs[nPos], nREG, pGPR, pStack );
327 break;
328 case typelib_TypeClass_CHAR:
329 case typelib_TypeClass_SHORT:
330 INSERT_INT16( pCppArgs[nPos], nREG, pGPR, pStack );
331 break;
332 case typelib_TypeClass_UNSIGNED_SHORT:
333 INSERT_UINT16( pCppArgs[nPos], nREG, pGPR, pStack );
334 break;
335 case typelib_TypeClass_BOOLEAN:
336 case typelib_TypeClass_BYTE:
337 INSERT_INT8( pCppArgs[nPos], nREG, pGPR, pStack );
338 break;
339 case typelib_TypeClass_FLOAT:
340 case typelib_TypeClass_DOUBLE:
341 INSERT_FLOAT_DOUBLE( pCppArgs[nPos], nREG, pFPR, pStack );
342 break;
343 case typelib_TypeClass_HYPER:
344 case typelib_TypeClass_UNSIGNED_HYPER:
345 INSERT_INT64( pCppArgs[nPos], nREG, pGPR, pStack );
346 break;
347 default:
348 break;
351 // no longer needed
352 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
354 else // ptr to complex value | ref
356 if (! rParam.bIn) // is pure out
358 // cpp out is constructed mem, uno out is not!
359 uno_constructData(
360 pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
361 pParamTypeDescr );
362 pTempIndices[nTempIndices] = nPos; // default constructed for cpp call
363 // will be released at reconversion
364 ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
366 // is in/inout
367 else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
369 uno_copyAndConvertData(
370 pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
371 pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
373 pTempIndices[nTempIndices] = nPos; // has to be reconverted
374 // will be released at reconversion
375 ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
377 else // direct way
379 pCppArgs[nPos] = pUnoArgs[nPos];
380 // no longer needed
381 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
383 INSERT_INT64( &(pCppArgs[nPos]), nREG, pGPR, pStack );
389 try {
390 callVirtualMethod(
391 pAdjustedThisPtr, aVtableSlot.index,
392 pCppReturn, pReturnTypeRef, bSimpleReturn,
393 pStackStart, ( pStack - pStackStart ),
394 pGPR, pFPR, nREG);
395 } catch (css::uno::Exception &) {
396 throw;
397 } catch (std::exception & e) {
398 throw css::uno::RuntimeException(
399 "C++ code threw " + o3tl::runtimeToOUString(typeid(e).name()) + ": "
400 + o3tl::runtimeToOUString(e.what()));
401 } catch (...) {
402 throw css::uno::RuntimeException("C++ code threw unknown exception");
404 // NO exception occurred...
405 *ppUnoExc = 0;
407 // reconvert temporary params
408 for ( ; nTempIndices--; )
410 sal_Int32 nIndex = pTempIndices[nTempIndices];
411 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
413 if (pParams[nIndex].bIn)
415 if (pParams[nIndex].bOut) // inout
417 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
418 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
419 pThis->getBridge()->getCpp2Uno() );
422 else // pure out
424 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
425 pThis->getBridge()->getCpp2Uno() );
427 // destroy temp cpp param => cpp: every param was constructed
428 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
430 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
432 // return value
433 if (pCppReturn && pUnoReturn != pCppReturn)
435 uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
436 pThis->getBridge()->getCpp2Uno() );
437 uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
440 catch (...)
442 // fill uno exception
443 CPPU_CURRENT_NAMESPACE::fillUnoException(*ppUnoExc, pThis->getBridge()->getCpp2Uno());
445 // temporary params
446 for ( ; nTempIndices--; )
448 sal_Int32 nIndex = pTempIndices[nTempIndices];
449 // destroy temp cpp param => cpp: every param was constructed
450 uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndices], cpp_release );
451 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
453 // return type
454 if (pReturnTypeDescr)
455 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
462 namespace bridges { namespace cpp_uno { namespace shared {
464 void unoInterfaceProxyDispatch(
465 uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
466 void * pReturn, void * pArgs[], uno_Any ** ppException )
468 // is my surrogate
469 bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
470 = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy *> (pUnoI);
471 //typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
473 #ifdef BRDEBUG
474 fprintf(stderr, "in dispatch\n");
475 #endif
477 switch (pMemberDescr->eTypeClass)
479 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
482 VtableSlot aVtableSlot(
483 getVtableSlot(
484 reinterpret_cast<
485 typelib_InterfaceAttributeTypeDescription const * >(
486 pMemberDescr)));
488 if (pReturn)
490 // dependent dispatch
491 cpp_call(
492 pThis, aVtableSlot,
493 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
494 0, 0, // no params
495 pReturn, pArgs, ppException );
497 else
499 // is SET
500 typelib_MethodParameter aParam;
501 aParam.pTypeRef =
502 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
503 aParam.bIn = sal_True;
504 aParam.bOut = sal_False;
506 typelib_TypeDescriptionReference * pReturnTypeRef = 0;
507 OUString aVoidName("void");
508 typelib_typedescriptionreference_new(
509 &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
511 // dependent dispatch
512 aVtableSlot.index += 1; //get then set method
513 cpp_call(
514 pThis, aVtableSlot,
515 pReturnTypeRef,
516 1, &aParam,
517 pReturn, pArgs, ppException );
519 typelib_typedescriptionreference_release( pReturnTypeRef );
522 break;
524 case typelib_TypeClass_INTERFACE_METHOD:
527 VtableSlot aVtableSlot(
528 getVtableSlot(
529 reinterpret_cast<
530 typelib_InterfaceMethodTypeDescription const * >(
531 pMemberDescr)));
532 switch (aVtableSlot.index)
534 // standard calls
535 case 1: // acquire uno interface
536 (*pUnoI->acquire)( pUnoI );
537 *ppException = 0;
538 break;
539 case 2: // release uno interface
540 (*pUnoI->release)( pUnoI );
541 *ppException = 0;
542 break;
543 case 0: // queryInterface() opt
545 typelib_TypeDescription * pTD = 0;
546 TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() );
547 if (pTD)
549 uno_Interface * pInterface = 0;
550 (*pThis->pBridge->getUnoEnv()->getRegisteredInterface)(pThis->pBridge->getUnoEnv(),
551 (void **)&pInterface, pThis->oid.pData,
552 (typelib_InterfaceTypeDescription *)pTD );
554 if (pInterface)
556 ::uno_any_construct(
557 reinterpret_cast< uno_Any * >( pReturn ),
558 &pInterface, pTD, 0 );
559 (*pInterface->release)( pInterface );
560 TYPELIB_DANGER_RELEASE( pTD );
561 *ppException = 0;
562 break;
564 TYPELIB_DANGER_RELEASE( pTD );
566 } // else perform queryInterface()
567 default:
568 // dependent dispatch
569 cpp_call(
570 pThis, aVtableSlot,
571 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef,
572 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams,
573 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams,
574 pReturn, pArgs, ppException );
576 break;
578 default:
580 ::com::sun::star::uno::RuntimeException aExc(
581 "illegal member type description!",
582 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
584 Type const & rExcType = cppu::UnoType<decltype(aExc)>::get();
585 // binary identical null reference
586 ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
592 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */