1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
21 #include <com/sun/star/uno/genfunc.hxx>
22 #include <sal/log.hxx>
24 #include <typelib/typedescription.hxx>
27 #include "cppinterfaceproxy.hxx"
29 #include "vtablefactory.hxx"
34 using namespace ::com::sun::star::uno
;
38 static typelib_TypeClass
cpp2uno_call(
39 bridges::cpp_uno::shared::CppInterfaceProxy
* pThis
,
40 const typelib_TypeDescription
* pMemberTypeDescr
,
41 typelib_TypeDescriptionReference
* pReturnTypeRef
, // 0 indicates void return
42 sal_Int32 nParams
, typelib_MethodParameter
* pParams
,
43 void ** gpreg
, void ** fpreg
, void ** ovrflw
,
44 sal_Int64
* pRegisterReturn
/* space for register return */ )
46 #if OSL_DEBUG_LEVEL > 2
47 fprintf(stderr
, "as far as cpp2uno_call\n");
49 int ng
= 0; //number of gpr registers used
50 int nf
= 0; //number of fpr registers used
52 // gpreg: [ret *], this, [gpr params]
53 // fpreg: [fpr params]
54 // ovrflw: [gpr or fpr params (properly aligned)]
57 typelib_TypeDescription
* pReturnTypeDescr
= 0;
59 TYPELIB_DANGER_GET( &pReturnTypeDescr
, pReturnTypeRef
);
61 void * pUnoReturn
= 0;
62 void * pCppReturn
= 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
66 if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr
))
68 pUnoReturn
= pRegisterReturn
; // direct way for simple types
70 else // complex return via ptr (pCppReturn)
72 pCppReturn
= *(void **)gpreg
;
76 pUnoReturn
= (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr
)
77 ? alloca( pReturnTypeDescr
->nSize
)
78 : pCppReturn
); // direct way
86 static_assert(sizeof(void *) == sizeof(sal_Int64
), "### unexpected size!");
88 void ** pUnoArgs
= (void **)alloca( 4 * sizeof(void *) * nParams
);
89 void ** pCppArgs
= pUnoArgs
+ nParams
;
90 // indices of values this have to be converted (interface conversion cpp<=>uno)
91 sal_Int32
* pTempIndices
= (sal_Int32
*)(pUnoArgs
+ (2 * nParams
));
92 // type descriptions for reconversions
93 typelib_TypeDescription
** ppTempParamTypeDescr
= (typelib_TypeDescription
**)(pUnoArgs
+ (3 * nParams
));
95 sal_Int32 nTempIndices
= 0;
96 for ( sal_Int32 nPos
= 0; nPos
< nParams
; ++nPos
)
98 const typelib_MethodParameter
& rParam
= pParams
[nPos
];
99 typelib_TypeDescription
* pParamTypeDescr
= 0;
100 TYPELIB_DANGER_GET( &pParamTypeDescr
, rParam
.pTypeRef
);
102 #if OSL_DEBUG_LEVEL > 2
103 fprintf(stderr
, "arg %d of %d\n", nPos
, nParams
);
106 if (!rParam
.bOut
&& bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr
)) // value
108 #if OSL_DEBUG_LEVEL > 2
109 fprintf(stderr
, "simple\n");
112 switch (pParamTypeDescr
->eTypeClass
)
114 case typelib_TypeClass_FLOAT
:
115 case typelib_TypeClass_DOUBLE
:
116 if (nf
< s390x::MAX_SSE_REGS
)
118 if (pParamTypeDescr
->eTypeClass
== typelib_TypeClass_FLOAT
)
120 float tmp
= (float) (*((double *)fpreg
));
121 (*((float *) fpreg
)) = tmp
;
124 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = fpreg
++;
129 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = ovrflw
;
133 case typelib_TypeClass_BYTE
:
134 case typelib_TypeClass_BOOLEAN
:
135 if (ng
< s390x::MAX_GPR_REGS
)
137 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = (((char *)gpreg
) + (sizeof(void*)-1));
143 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = (((char *)ovrflw
) + (sizeof(void*)-1));
147 case typelib_TypeClass_CHAR
:
148 case typelib_TypeClass_SHORT
:
149 case typelib_TypeClass_UNSIGNED_SHORT
:
150 if (ng
< s390x::MAX_GPR_REGS
)
152 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = (((char *)gpreg
) + (sizeof(void*)-2));
158 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = (((char *)ovrflw
) + (sizeof(void*)-2));
162 case typelib_TypeClass_ENUM
:
163 case typelib_TypeClass_LONG
:
164 case typelib_TypeClass_UNSIGNED_LONG
:
165 if (ng
< s390x::MAX_GPR_REGS
)
167 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = (((char *)gpreg
) + (sizeof(void*)-4));
173 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = (((char *)ovrflw
) + (sizeof(void*)-4));
178 if (ng
< s390x::MAX_GPR_REGS
)
180 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = gpreg
++;
185 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = ovrflw
;
192 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
194 else // ptr to complex value | ref
196 #if OSL_DEBUG_LEVEL > 2
197 fprintf(stderr
, "complex, ng is %d\n", ng
);
200 void *pCppStack
; //temporary stack pointer
202 if (ng
< s390x::MAX_GPR_REGS
)
204 pCppArgs
[nPos
] = pCppStack
= *gpreg
++;
209 pCppArgs
[nPos
] = pCppStack
= *ovrflw
;
213 if (! rParam
.bIn
) // is pure out
215 // uno out is unconstructed mem!
216 pUnoArgs
[nPos
] = alloca( pParamTypeDescr
->nSize
);
217 pTempIndices
[nTempIndices
] = nPos
;
218 // will be released at reconversion
219 ppTempParamTypeDescr
[nTempIndices
++] = pParamTypeDescr
;
222 else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr
))
224 uno_copyAndConvertData( pUnoArgs
[nPos
] = alloca( pParamTypeDescr
->nSize
),
225 pCppStack
, pParamTypeDescr
,
226 pThis
->getBridge()->getCpp2Uno() );
227 pTempIndices
[nTempIndices
] = nPos
; // has to be reconverted
228 // will be released at reconversion
229 ppTempParamTypeDescr
[nTempIndices
++] = pParamTypeDescr
;
233 pUnoArgs
[nPos
] = pCppStack
;
235 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
240 #if OSL_DEBUG_LEVEL > 2
241 fprintf(stderr
, "end of params\n");
245 uno_Any aUnoExc
; // Any will be constructed by callee
246 uno_Any
* pUnoExc
= &aUnoExc
;
248 // invoke uno dispatch call
249 (*pThis
->getUnoI()->pDispatcher
)( pThis
->getUnoI(), pMemberTypeDescr
, pUnoReturn
, pUnoArgs
, &pUnoExc
);
251 // in case an exception occurred...
254 // destruct temporary in/inout params
255 for ( ; nTempIndices
--; )
257 sal_Int32 nIndex
= pTempIndices
[nTempIndices
];
259 if (pParams
[nIndex
].bIn
) // is in/inout => was constructed
260 uno_destructData( pUnoArgs
[nIndex
], ppTempParamTypeDescr
[nTempIndices
], 0 );
261 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr
[nTempIndices
] );
263 if (pReturnTypeDescr
)
264 TYPELIB_DANGER_RELEASE( pReturnTypeDescr
);
266 CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc
, pThis
->getBridge()->getUno2Cpp() ); // has to destruct the any
268 return typelib_TypeClass_VOID
;
270 else // else no exception occurred...
273 for ( ; nTempIndices
--; )
275 sal_Int32 nIndex
= pTempIndices
[nTempIndices
];
276 typelib_TypeDescription
* pParamTypeDescr
= ppTempParamTypeDescr
[nTempIndices
];
278 if (pParams
[nIndex
].bOut
) // inout/out
280 // convert and assign
281 uno_destructData( pCppArgs
[nIndex
], pParamTypeDescr
, cpp_release
);
282 uno_copyAndConvertData( pCppArgs
[nIndex
], pUnoArgs
[nIndex
], pParamTypeDescr
,
283 pThis
->getBridge()->getUno2Cpp() );
285 // destroy temp uno param
286 uno_destructData( pUnoArgs
[nIndex
], pParamTypeDescr
, 0 );
288 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
291 if (pCppReturn
) // has complex return
293 if (pUnoReturn
!= pCppReturn
) // needs reconversion
295 uno_copyAndConvertData( pCppReturn
, pUnoReturn
, pReturnTypeDescr
,
296 pThis
->getBridge()->getUno2Cpp() );
297 // destroy temp uno return
298 uno_destructData( pUnoReturn
, pReturnTypeDescr
, 0 );
300 // complex return ptr is set to return reg
301 *(void **)pRegisterReturn
= pCppReturn
;
303 if (pReturnTypeDescr
)
305 typelib_TypeClass eRet
= (typelib_TypeClass
)pReturnTypeDescr
->eTypeClass
;
306 TYPELIB_DANGER_RELEASE( pReturnTypeDescr
);
310 return typelib_TypeClass_VOID
;
315 static typelib_TypeClass
cpp_mediate(
316 sal_uInt64 nOffsetAndIndex
,
317 void ** gpreg
, void ** fpreg
, void ** ovrflw
,
318 sal_Int64
* pRegisterReturn
/* space for register return */ )
320 static_assert(sizeof(sal_Int64
)==sizeof(void *), "### unexpected!");
322 sal_Int32 nVtableOffset
= (nOffsetAndIndex
>> 32);
323 sal_Int32 nFunctionIndex
= (nOffsetAndIndex
& 0xFFFFFFFF);
325 #if OSL_DEBUG_LEVEL > 2
326 fprintf(stderr
, "nVTableOffset, nFunctionIndex are %x %x\n", nVtableOffset
, nFunctionIndex
);
329 #if OSL_DEBUG_LEVEL > 2
330 // Let's figure out what is really going on here
332 fprintf( stderr
, "= cpp_mediate () =\nGPR's (%d): ", 5 );
333 for ( unsigned int i
= 0; i
< 5; ++i
)
334 fprintf( stderr
, "0x%lx, ", gpreg
[i
] );
335 fprintf( stderr
, "\n");
336 fprintf( stderr
, "\nFPR's (%d): ", 4 );
337 for ( unsigned int i
= 0; i
< 4; ++i
)
338 fprintf( stderr
, "0x%lx (%f), ", fpreg
[i
], fpreg
[i
] );
339 fprintf( stderr
, "\n");
344 // gpreg: [ret *], this, [other gpr params]
345 // fpreg: [fpr params]
346 // ovrflw: [gpr or fpr params (properly aligned)]
348 // _this_ ptr is patched cppu_XInterfaceProxy object
350 if( nFunctionIndex
& 0x80000000 )
352 nFunctionIndex
&= 0x7fffffff;
360 pThis
= static_cast< char * >(pThis
) - nVtableOffset
;
362 bridges::cpp_uno::shared::CppInterfaceProxy
* pCppI
363 = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
366 typelib_InterfaceTypeDescription
* pTypeDescr
= pCppI
->getTypeDescr();
369 if (nFunctionIndex
>= pTypeDescr
->nMapFunctionIndexToMemberIndex
)
373 "illegal " << OUString::unacquired(&pTypeDescr
->aBase
.pTypeName
)
374 << " vtable index " << nFunctionIndex
<< "/"
375 << pTypeDescr
->nMapFunctionIndexToMemberIndex
);
376 throw RuntimeException(
377 ("illegal " + OUString::unacquired(&pTypeDescr
->aBase
.pTypeName
)
378 + " vtable index " + OUString::number(nFunctionIndex
) + "/"
379 + OUString::number(pTypeDescr
->nMapFunctionIndexToMemberIndex
)),
380 (XInterface
*)pCppI
);
383 // determine called method
384 sal_Int32 nMemberPos
= pTypeDescr
->pMapFunctionIndexToMemberIndex
[nFunctionIndex
];
385 assert(nMemberPos
< pTypeDescr
->nAllMembers
);
387 TypeDescription
aMemberDescr( pTypeDescr
->ppAllMembers
[nMemberPos
] );
389 typelib_TypeClass eRet
;
390 switch (aMemberDescr
.get()->eTypeClass
)
392 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
394 if (pTypeDescr
->pMapMemberIndexToFunctionIndex
[nMemberPos
] == nFunctionIndex
)
398 pCppI
, aMemberDescr
.get(),
399 ((typelib_InterfaceAttributeTypeDescription
*)aMemberDescr
.get())->pAttributeTypeRef
,
401 gpreg
, fpreg
, ovrflw
, pRegisterReturn
);
406 typelib_MethodParameter aParam
;
408 ((typelib_InterfaceAttributeTypeDescription
*)aMemberDescr
.get())->pAttributeTypeRef
;
409 aParam
.bIn
= sal_True
;
410 aParam
.bOut
= sal_False
;
413 pCppI
, aMemberDescr
.get(),
414 0, // indicates void return
416 gpreg
, fpreg
, ovrflw
, pRegisterReturn
);
420 case typelib_TypeClass_INTERFACE_METHOD
:
423 switch (nFunctionIndex
)
426 pCppI
->acquireProxy(); // non virtual call!
427 eRet
= typelib_TypeClass_VOID
;
430 pCppI
->releaseProxy(); // non virtual call!
431 eRet
= typelib_TypeClass_VOID
;
433 case 0: // queryInterface() opt
435 typelib_TypeDescription
* pTD
= 0;
436 TYPELIB_DANGER_GET( &pTD
, reinterpret_cast< Type
* >( gpreg
[2] )->getTypeLibType() );
439 XInterface
* pInterface
= 0;
440 (*pCppI
->getBridge()->getCppEnv()->getRegisteredInterface
)(
441 pCppI
->getBridge()->getCppEnv(),
442 (void **)&pInterface
, pCppI
->getOid().pData
,
443 (typelib_InterfaceTypeDescription
*)pTD
);
448 reinterpret_cast< uno_Any
* >( gpreg
[0] ),
449 &pInterface
, pTD
, cpp_acquire
);
450 pInterface
->release();
451 TYPELIB_DANGER_RELEASE( pTD
);
452 *(void **)pRegisterReturn
= gpreg
[0];
453 eRet
= typelib_TypeClass_ANY
;
456 TYPELIB_DANGER_RELEASE( pTD
);
458 } // else perform queryInterface()
461 pCppI
, aMemberDescr
.get(),
462 ((typelib_InterfaceMethodTypeDescription
*)aMemberDescr
.get())->pReturnTypeRef
,
463 ((typelib_InterfaceMethodTypeDescription
*)aMemberDescr
.get())->nParams
,
464 ((typelib_InterfaceMethodTypeDescription
*)aMemberDescr
.get())->pParams
,
465 gpreg
, fpreg
, ovrflw
, pRegisterReturn
);
471 throw RuntimeException( "no member description found!", (XInterface
*)pCppI
);
478 long privateSnippetExecutor(long r2
, long r3
, long r4
, long r5
, long r6
, long firstonstack
)
480 register long r0
asm("r0");
481 sal_uInt64 nOffsetAndIndex
= r0
;
483 long sp
= (long)&firstonstack
;
485 sal_uInt64 gpreg
[s390x::MAX_GPR_REGS
];
492 double fpreg
[s390x::MAX_SSE_REGS
];
493 register double f0
asm("f0"); fpreg
[0] = f0
;
494 register double f2
asm("f2"); fpreg
[1] = f2
;
495 register double f4
asm("f4"); fpreg
[2] = f4
;
496 register double f6
asm("f6"); fpreg
[3] = f6
;
498 volatile long nRegReturn
[1];
499 #if OSL_DEBUG_LEVEL > 2
500 fprintf(stderr
, "before mediate with %lx\n",nOffsetAndIndex
);
501 fprintf(stderr
, "doubles are %f %f %f %f\n", fpreg
[0], fpreg
[1], fpreg
[2], fpreg
[3]);
503 typelib_TypeClass aType
=
504 cpp_mediate( nOffsetAndIndex
, (void**)gpreg
, (void**)fpreg
, (void**)sp
,
505 (sal_Int64
*)nRegReturn
);
506 #if OSL_DEBUG_LEVEL > 2
507 fprintf(stderr
, "after mediate ret is %lx %ld\n", nRegReturn
[0], nRegReturn
[0]);
512 case typelib_TypeClass_BOOLEAN
:
513 case typelib_TypeClass_BYTE
:
514 nRegReturn
[0] = (unsigned long)(*(unsigned char *)nRegReturn
);
516 case typelib_TypeClass_CHAR
:
517 case typelib_TypeClass_UNSIGNED_SHORT
:
518 case typelib_TypeClass_SHORT
:
519 nRegReturn
[0] = (unsigned long)(*(unsigned short *)nRegReturn
);
521 case typelib_TypeClass_ENUM
:
522 case typelib_TypeClass_UNSIGNED_LONG
:
523 case typelib_TypeClass_LONG
:
524 nRegReturn
[0] = (unsigned long)(*(unsigned int *)nRegReturn
);
526 case typelib_TypeClass_VOID
:
529 case typelib_TypeClass_FLOAT
:
531 double tmp
= (double) (*((float *)nRegReturn
));
532 (*((double *) nRegReturn
)) = tmp
;
534 //deliberate fall through
535 case typelib_TypeClass_DOUBLE
:
536 __asm__ ( "ld 0,%0\n\t"
537 : : "m" (*((double*)nRegReturn
)) );
540 return nRegReturn
[0];
543 const int codeSnippetSize
= 32;
545 unsigned char *codeSnippet( unsigned char * code
, sal_Int32 nFunctionIndex
, sal_Int32 nVtableOffset
, bool simple_ret_type
)
547 sal_uInt64 nOffsetAndIndex
= ( ( (sal_uInt64
) nVtableOffset
) << 32 ) | ( (sal_Int64
) nFunctionIndex
);
549 if (! simple_ret_type
)
550 nOffsetAndIndex
|= 0x80000000;
552 unsigned char * p
= code
;
553 *(short *)&p
[0] = 0x0d10; /* basr %r1,0 */
554 *(short *)&p
[2] = 0xeb01; /* lmg %r0,%r1,14(%r1) */
555 *(short *)&p
[4] = 0x100e;
556 *(short *)&p
[6] = 0x0004;
557 *(short *)&p
[8] = 0x07f1; /* br %r1 */
558 *(long *)&p
[16] = (long)nOffsetAndIndex
;
559 *(long *)&p
[24] = (long)&privateSnippetExecutor
;
560 return (code
+ codeSnippetSize
);
564 void bridges::cpp_uno::shared::VtableFactory::flushCode(unsigned char const *, unsigned char const *)
568 struct bridges::cpp_uno::shared::VtableFactory::Slot
{ void * fn
; };
570 bridges::cpp_uno::shared::VtableFactory::Slot
*
571 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block
)
573 return static_cast< Slot
* >(block
) + 2;
576 std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(
579 return (slotCount
+ 2) * sizeof (Slot
) + slotCount
* codeSnippetSize
;
582 bridges::cpp_uno::shared::VtableFactory::Slot
*
583 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
584 void * block
, sal_Int32 slotCount
, sal_Int32
,
585 typelib_InterfaceTypeDescription
*)
587 Slot
* slots
= mapBlockToVtable(block
);
590 return slots
+ slotCount
;
593 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
594 Slot
** slots
, unsigned char * code
, sal_PtrDiff writetoexecdiff
,
595 typelib_InterfaceTypeDescription
const * type
, sal_Int32 functionOffset
,
596 sal_Int32 functionCount
, sal_Int32 vtableOffset
)
598 (*slots
) -= functionCount
;
600 #if OSL_DEBUG_LEVEL > 2
601 fprintf(stderr
, "in addLocalFunctions functionOffset is %x\n",functionOffset
);
602 fprintf(stderr
, "in addLocalFunctions vtableOffset is %x\n",vtableOffset
);
605 for (sal_Int32 i
= 0; i
< type
->nMembers
; ++i
) {
606 typelib_TypeDescription
* member
= 0;
607 TYPELIB_DANGER_GET(&member
, type
->ppMembers
[i
]);
609 switch (member
->eTypeClass
) {
610 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
612 (s
++)->fn
= code
+ writetoexecdiff
;
614 code
, functionOffset
++, vtableOffset
,
615 bridges::cpp_uno::shared::isSimpleType(
617 typelib_InterfaceAttributeTypeDescription
* >(
618 member
)->pAttributeTypeRef
));
621 if (!reinterpret_cast<
622 typelib_InterfaceAttributeTypeDescription
* >(
625 (s
++)->fn
= code
+ writetoexecdiff
;
626 code
= codeSnippet(code
, functionOffset
++, vtableOffset
, true);
630 case typelib_TypeClass_INTERFACE_METHOD
:
631 (s
++)->fn
= code
+ writetoexecdiff
;
633 code
, functionOffset
++, vtableOffset
,
634 bridges::cpp_uno::shared::isSimpleType(
636 typelib_InterfaceMethodTypeDescription
* >(
637 member
)->pReturnTypeRef
));
644 TYPELIB_DANGER_RELEASE(member
);
649 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */