1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: cpp2uno.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_bridges.hxx"
34 #include <com/sun/star/uno/genfunc.hxx>
36 #include <typelib/typedescription.hxx>
38 #include "bridges/cpp_uno/shared/bridge.hxx"
39 #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx"
40 #include "bridges/cpp_uno/shared/types.hxx"
41 #include "bridges/cpp_uno/shared/vtablefactory.hxx"
45 using namespace ::com::sun::star::uno
;
50 //==================================================================================================
51 static typelib_TypeClass
cpp2uno_call(
52 bridges::cpp_uno::shared::CppInterfaceProxy
* pThis
,
53 const typelib_TypeDescription
* pMemberTypeDescr
,
54 typelib_TypeDescriptionReference
* pReturnTypeRef
, // 0 indicates void return
55 sal_Int32 nParams
, typelib_MethodParameter
* pParams
,
56 void ** gpreg
, void ** fpreg
, void ** ovrflw
,
57 sal_Int64
* pRegisterReturn
/* space for register return */ )
60 // gpreg: [ret *], this, [gpr params]
61 // fpreg: [fpr params]
62 // ovrflw: [gpr or fpr params (space for entire parameter list in structure format properly aligned)]
65 typelib_TypeDescription
* pReturnTypeDescr
= 0;
67 TYPELIB_DANGER_GET( &pReturnTypeDescr
, pReturnTypeRef
);
69 void * pUnoReturn
= 0;
70 void * pCppReturn
= 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
78 if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr
))
79 pUnoReturn
= pRegisterReturn
; // direct way for simple types
80 else // complex return via ptr (pCppReturn)
86 pUnoReturn
= (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr
)
87 ? alloca( pReturnTypeDescr
->nSize
)
88 : pCppReturn
); // direct way
95 // after handling optional return pointer and "this"
96 // make use of the space that is allocated to store all parameters in the callers stack
97 // by comying the proper registers filled with parameters to that space
98 char * pCppStack
= (char *)ovrflw
;
103 for ( nPos
= 0; nPos
< nParams
; ++nPos
)
105 const typelib_MethodParameter
& rParam
= pParams
[nPos
];
110 *(sal_Int32
*)pCppStack
= ((sal_Int32
*)gpreg
)[ngpreg
++];
112 pCppStack
+= sizeof (sal_Int32
);
116 switch (rParam
.pTypeRef
->eTypeClass
)
118 case typelib_TypeClass_FLOAT
:
121 *(float *)pCppStack
= ((double *)fpreg
)[nfpreg
++];
123 pCppStack
+= sizeof (float);
126 case typelib_TypeClass_DOUBLE
:
129 *(double *)pCppStack
= ((double *)fpreg
)[nfpreg
++];
131 pCppStack
+= sizeof (double);
134 case typelib_TypeClass_UNSIGNED_HYPER
:
135 case typelib_TypeClass_HYPER
:
138 *(sal_Int32
*)pCppStack
= ((sal_Int32
*)gpreg
)[ngpreg
++];
140 pCppStack
+= sizeof (sal_Int32
);
141 // fall through on purpose
145 *(sal_Int32
*)pCppStack
= ((sal_Int32
*)gpreg
)[ngpreg
++];
147 pCppStack
+= sizeof (sal_Int32
);
152 // now the stack has all of the paramters stored in it ready to be processed
153 // so we are ready to build the uno call stack
154 pCppStack
= (char *)ovrflw
;
157 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32
), "### unexpected size!" );
160 void ** pUnoArgs
= (void **)alloca( 4 * sizeof(void *) * nParams
);
161 void ** pCppArgs
= pUnoArgs
+ nParams
;
163 // indizes of values this have to be converted (interface conversion cpp<=>uno)
164 sal_Int32
* pTempIndizes
= (sal_Int32
*)(pUnoArgs
+ (2 * nParams
));
166 // type descriptions for reconversions
167 typelib_TypeDescription
** ppTempParamTypeDescr
= (typelib_TypeDescription
**)(pUnoArgs
+ (3 * nParams
));
169 sal_Int32 nTempIndizes
= 0;
171 for ( nPos
= 0; nPos
< nParams
; ++nPos
)
173 const typelib_MethodParameter
& rParam
= pParams
[nPos
];
174 typelib_TypeDescription
* pParamTypeDescr
= 0;
175 TYPELIB_DANGER_GET( &pParamTypeDescr
, rParam
.pTypeRef
);
177 if (!rParam
.bOut
&& bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr
))
180 switch (pParamTypeDescr
->eTypeClass
)
182 case typelib_TypeClass_BOOLEAN
:
183 case typelib_TypeClass_BYTE
:
184 pCppArgs
[nPos
] = pCppStack
+3;
185 pUnoArgs
[nPos
] = pCppStack
+3;
187 case typelib_TypeClass_CHAR
:
188 case typelib_TypeClass_SHORT
:
189 case typelib_TypeClass_UNSIGNED_SHORT
:
190 pCppArgs
[nPos
] = pCppStack
+2;
191 pUnoArgs
[nPos
] = pCppStack
+2;
193 case typelib_TypeClass_HYPER
:
194 case typelib_TypeClass_UNSIGNED_HYPER
:
195 case typelib_TypeClass_DOUBLE
:
196 pCppArgs
[nPos
] = pCppStack
;
197 pUnoArgs
[nPos
] = pCppStack
;
198 pCppStack
+= sizeof(sal_Int32
); // extra long (two regs)
201 pCppArgs
[nPos
] = pCppStack
;
202 pUnoArgs
[nPos
] = pCppStack
;
205 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
207 else // ptr to complex value | ref
209 pCppArgs
[nPos
] = *(void **)pCppStack
;
211 if (! rParam
.bIn
) // is pure out
213 // uno out is unconstructed mem!
214 pUnoArgs
[nPos
] = alloca( pParamTypeDescr
->nSize
);
215 pTempIndizes
[nTempIndizes
] = nPos
;
216 // will be released at reconversion
217 ppTempParamTypeDescr
[nTempIndizes
++] = pParamTypeDescr
;
220 else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr
))
222 uno_copyAndConvertData( pUnoArgs
[nPos
] = alloca( pParamTypeDescr
->nSize
),
223 *(void **)pCppStack
, pParamTypeDescr
,
224 pThis
->getBridge()->getCpp2Uno() );
225 pTempIndizes
[nTempIndizes
] = nPos
; // has to be reconverted
226 // will be released at reconversion
227 ppTempParamTypeDescr
[nTempIndizes
++] = pParamTypeDescr
;
231 pUnoArgs
[nPos
] = *(void **)pCppStack
;
233 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
236 pCppStack
+= sizeof(sal_Int32
); // standard parameter length
241 uno_Any aUnoExc
; // Any will be constructed by callee
242 uno_Any
* pUnoExc
= &aUnoExc
;
244 // invoke uno dispatch call
245 (*pThis
->getUnoI()->pDispatcher
)(
246 pThis
->getUnoI(), pMemberTypeDescr
, pUnoReturn
, pUnoArgs
, &pUnoExc
);
248 // in case an exception occured...
251 // destruct temporary in/inout params
252 for ( ; nTempIndizes
--; )
254 sal_Int32 nIndex
= pTempIndizes
[nTempIndizes
];
256 if (pParams
[nIndex
].bIn
) // is in/inout => was constructed
257 uno_destructData( pUnoArgs
[nIndex
], ppTempParamTypeDescr
[nTempIndizes
], 0 );
258 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr
[nTempIndizes
] );
260 if (pReturnTypeDescr
)
261 TYPELIB_DANGER_RELEASE( pReturnTypeDescr
);
263 CPPU_CURRENT_NAMESPACE::raiseException(
264 &aUnoExc
, pThis
->getBridge()->getUno2Cpp() );
265 // has to destruct the any
267 return typelib_TypeClass_VOID
;
269 else // else no exception occured...
272 for ( ; nTempIndizes
--; )
274 sal_Int32 nIndex
= pTempIndizes
[nTempIndizes
];
275 typelib_TypeDescription
* pParamTypeDescr
= ppTempParamTypeDescr
[nTempIndizes
];
277 if (pParams
[nIndex
].bOut
) // inout/out
279 // convert and assign
280 uno_destructData( pCppArgs
[nIndex
], pParamTypeDescr
, cpp_release
);
281 uno_copyAndConvertData( pCppArgs
[nIndex
], pUnoArgs
[nIndex
], pParamTypeDescr
,
282 pThis
->getBridge()->getUno2Cpp() );
284 // destroy temp uno param
285 uno_destructData( pUnoArgs
[nIndex
], pParamTypeDescr
, 0 );
287 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
290 if (pCppReturn
) // has complex return
292 if (pUnoReturn
!= pCppReturn
) // needs reconversion
294 uno_copyAndConvertData( pCppReturn
, pUnoReturn
, pReturnTypeDescr
,
295 pThis
->getBridge()->getUno2Cpp() );
296 // destroy temp uno return
297 uno_destructData( pUnoReturn
, pReturnTypeDescr
, 0 );
299 // complex return ptr is set to return reg
300 *(void **)pRegisterReturn
= pCppReturn
;
302 if (pReturnTypeDescr
)
304 typelib_TypeClass eRet
= (typelib_TypeClass
)pReturnTypeDescr
->eTypeClass
;
305 TYPELIB_DANGER_RELEASE( pReturnTypeDescr
);
309 return typelib_TypeClass_VOID
;
314 //==================================================================================================
315 static typelib_TypeClass
cpp_mediate(
316 sal_Int32 nFunctionIndex
,
317 sal_Int32 nVtableOffset
,
318 void ** gpreg
, void ** fpreg
, void ** ovrflw
,
319 sal_Int64
* pRegisterReturn
/* space for register return */ )
321 OSL_ENSURE( sizeof(sal_Int32
)==sizeof(void *), "### unexpected!" );
323 // gpreg: [ret *], this, [other gpr params]
324 // fpreg: [fpr params]
325 // ovrflw: [gpr or fpr params (in space allocated for all params properly aligned)]
328 if( nFunctionIndex
& 0x80000000 )
330 nFunctionIndex
&= 0x7fffffff;
338 pThis
= static_cast< char * >(pThis
) - nVtableOffset
;
339 bridges::cpp_uno::shared::CppInterfaceProxy
* pCppI
340 = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(pThis
);
343 typelib_InterfaceTypeDescription
* pTypeDescr
= pCppI
->getTypeDescr();
345 OSL_ENSURE( nFunctionIndex
< pTypeDescr
->nMapFunctionIndexToMemberIndex
, "### illegal vtable index!" );
346 if (nFunctionIndex
>= pTypeDescr
->nMapFunctionIndexToMemberIndex
)
348 throw RuntimeException(
349 rtl::OUString::createFromAscii("illegal vtable index!"),
350 (XInterface
*)pThis
);
353 // determine called method
354 sal_Int32 nMemberPos
= pTypeDescr
->pMapFunctionIndexToMemberIndex
[nFunctionIndex
];
355 OSL_ENSURE( nMemberPos
< pTypeDescr
->nAllMembers
, "### illegal member index!" );
357 TypeDescription
aMemberDescr( pTypeDescr
->ppAllMembers
[nMemberPos
] );
359 typelib_TypeClass eRet
;
360 switch (aMemberDescr
.get()->eTypeClass
)
362 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
364 if (pTypeDescr
->pMapMemberIndexToFunctionIndex
[nMemberPos
] == nFunctionIndex
)
368 pCppI
, aMemberDescr
.get(),
369 ((typelib_InterfaceAttributeTypeDescription
*)aMemberDescr
.get())->pAttributeTypeRef
,
371 gpreg
, fpreg
, ovrflw
, pRegisterReturn
);
376 typelib_MethodParameter aParam
;
378 ((typelib_InterfaceAttributeTypeDescription
*)aMemberDescr
.get())->pAttributeTypeRef
;
379 aParam
.bIn
= sal_True
;
380 aParam
.bOut
= sal_False
;
383 pCppI
, aMemberDescr
.get(),
384 0, // indicates void return
386 gpreg
, fpreg
, ovrflw
, pRegisterReturn
);
390 case typelib_TypeClass_INTERFACE_METHOD
:
393 switch (nFunctionIndex
)
396 pCppI
->acquireProxy(); // non virtual call!
397 eRet
= typelib_TypeClass_VOID
;
400 pCppI
->releaseProxy(); // non virtual call!
401 eRet
= typelib_TypeClass_VOID
;
403 case 0: // queryInterface() opt
405 typelib_TypeDescription
* pTD
= 0;
406 TYPELIB_DANGER_GET( &pTD
, reinterpret_cast< Type
* >( gpreg
[2] )->getTypeLibType() );
409 XInterface
* pInterface
= 0;
410 (*pCppI
->getBridge()->getCppEnv()->getRegisteredInterface
)(
411 pCppI
->getBridge()->getCppEnv(),
412 (void **)&pInterface
, pCppI
->getOid().pData
, (typelib_InterfaceTypeDescription
*)pTD
);
417 reinterpret_cast< uno_Any
* >( gpreg
[0] ),
418 &pInterface
, pTD
, cpp_acquire
);
419 pInterface
->release();
420 TYPELIB_DANGER_RELEASE( pTD
);
421 *(void **)pRegisterReturn
= gpreg
[0];
422 eRet
= typelib_TypeClass_ANY
;
425 TYPELIB_DANGER_RELEASE( pTD
);
427 } // else perform queryInterface()
430 pCppI
, aMemberDescr
.get(),
431 ((typelib_InterfaceMethodTypeDescription
*)aMemberDescr
.get())->pReturnTypeRef
,
432 ((typelib_InterfaceMethodTypeDescription
*)aMemberDescr
.get())->nParams
,
433 ((typelib_InterfaceMethodTypeDescription
*)aMemberDescr
.get())->pParams
,
434 gpreg
, fpreg
, ovrflw
, pRegisterReturn
);
440 throw RuntimeException(
441 rtl::OUString::createFromAscii("no member description found!"),
442 (XInterface
*)pThis
);
444 eRet
= typelib_TypeClass_VOID
;
451 //==================================================================================================
453 * is called on incoming vtable calls
454 * (called by asm snippets)
456 static void cpp_vtable_call( int nFunctionIndex
, int nVtableOffset
, void** gpregptr
, void** fpregptr
, void** ovrflw
)
461 // FIXME: why are we restoring the volatile ctr register here
462 sal_Int32 ctrsave
= ((sal_Int32
*)gpregptr
)[-1];
464 memcpy( gpreg
, gpregptr
, 32);
465 memcpy( fpreg
, fpregptr
, 104);
467 volatile long nRegReturn
[2];
469 // sal_Bool bComplex = nFunctionIndex & 0x80000000 ? sal_True : sal_False;
471 typelib_TypeClass aType
=
472 cpp_mediate( nFunctionIndex
, nVtableOffset
, (void**)gpreg
, (void**)fpreg
, ovrflw
, (sal_Int64
*)nRegReturn
);
474 // FIXME: why are we restoring the volatile ctr register here
475 // FIXME: and why are we putting back the values for r4, r5, and r6 as well
476 // FIXME: this makes no sense to me, all of these registers are volatile!
477 __asm__( "lwz r4, %0\n\t"
482 : : "m"(ctrsave
), "m"(gpreg
[1]), "m"(gpreg
[2]), "m"(gpreg
[3]) );
487 // move return value into register space
488 // (will be loaded by machine code snippet)
490 case typelib_TypeClass_BOOLEAN
:
491 case typelib_TypeClass_BYTE
:
492 __asm__( "lbz r3,%0\n\t" : :
493 "m"(nRegReturn
[0]) );
496 case typelib_TypeClass_CHAR
:
497 case typelib_TypeClass_SHORT
:
498 case typelib_TypeClass_UNSIGNED_SHORT
:
499 __asm__( "lhz r3,%0\n\t" : :
500 "m"(nRegReturn
[0]) );
503 case typelib_TypeClass_FLOAT
:
504 __asm__( "lfs f1,%0\n\t" : :
505 "m" (*((float*)nRegReturn
)) );
508 case typelib_TypeClass_DOUBLE
:
509 __asm__( "lfd f1,%0\n\t" : :
510 "m" (*((double*)nRegReturn
)) );
513 case typelib_TypeClass_HYPER
:
514 case typelib_TypeClass_UNSIGNED_HYPER
:
515 __asm__( "lwz r4,%0\n\t" : :
516 "m"(nRegReturn
[1]) ); // fall through
519 __asm__( "lwz r3,%0\n\t" : :
520 "m"(nRegReturn
[0]) );
526 int const codeSnippetSize
= 136;
528 unsigned char * codeSnippet( unsigned char * code
, sal_Int32 functionIndex
,
529 sal_Int32 vtableOffset
, bool simpleRetType
)
531 if (! simpleRetType
)
532 functionIndex
|= 0x80000000;
534 // OSL_ASSERT( sizeof (long) == 4 );
536 // FIXME: why are we leaving an 8k gap in the stack here
537 // FIXME: is this to allow room for signal handling frames?
538 // FIXME: seems like overkill here but this is what was done for Mac OSX for gcc2
539 // FIXME: also why no saving of the non-volatile CR pieces here, to be safe
540 // FIXME: we probably should
542 /* generate this code */
544 // # so first save gpr 3 to gpr 10 (aligned to 4)
554 // # next save fpr 1 to fpr 13 (aligned to 8)
555 // stfd f1, -7968(r1)
556 // stfd f2, -7960(r1)
557 // stfd f3, -7952(r1)
558 // stfd f4, -7944(r1)
559 // stfd f5, -7936(r1)
560 // stfd f6, -7928(r1)
561 // stfd f7, -7920(r1)
562 // stfd f8, -7912(r1)
563 // stfd f9, -7904(r1)
564 // stfd f10,-7896(r1)
565 // stfd f11,-7888(r1)
566 // stfd f12,-7880(r1)
567 // stfd f13,-7872(r1)
569 // FIXME: ctr is volatile, while are we saving it and not CR?
573 // # now here is where cpp_vtable_call must go
578 // # now load up the functionIndex number
582 // # now load up the vtableOffset
586 // #now load up the pointer to the saved gpr registers
589 // #now load up the pointer to the saved fpr registers
592 // #now load up the pointer to the overflow call stack
593 // addi r7,r1,24 # frame pointer plus 24
597 unsigned long * p
= (unsigned long *) code
;
622 * p
++ = 0x3c600000 | (((unsigned long)cpp_vtable_call
) >> 16);
623 * p
++ = 0x60630000 | (((unsigned long)cpp_vtable_call
) & 0x0000FFFF);
625 * p
++ = 0x3c600000 | (((unsigned long)functionIndex
) >> 16);
626 * p
++ = 0x60630000 | (((unsigned long)functionIndex
) & 0x0000FFFF);
627 * p
++ = 0x3c800000 | (((unsigned long)vtableOffset
) >> 16);
628 * p
++ = 0x60840000 | (((unsigned long)vtableOffset
) & 0x0000FFFF);
634 return (code
+ codeSnippetSize
);
641 void bridges::cpp_uno::shared::VtableFactory::flushCode(unsigned char const * bptr
, unsigned char const * eptr
)
643 int const lineSize
= 32;
644 for (unsigned char const * p
= bptr
; p
< eptr
+ lineSize
; p
+= lineSize
) {
645 __asm__
volatile ("dcbst 0, %0" : : "r"(p
) : "memory");
647 __asm__
volatile ("sync" : : : "memory");
648 for (unsigned char const * p
= bptr
; p
< eptr
+ lineSize
; p
+= lineSize
) {
649 __asm__
volatile ("icbi 0, %0" : : "r"(p
) : "memory");
651 __asm__
volatile ("isync" : : : "memory");
654 struct bridges::cpp_uno::shared::VtableFactory::Slot
{ void * fn
; };
656 bridges::cpp_uno::shared::VtableFactory::Slot
*
657 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block
)
659 return static_cast< Slot
* >(block
) + 2;
662 sal_Size
bridges::cpp_uno::shared::VtableFactory::getBlockSize(
665 return (slotCount
+ 2) * sizeof (Slot
) + slotCount
* codeSnippetSize
;
668 bridges::cpp_uno::shared::VtableFactory::Slot
*
669 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
670 void * block
, sal_Int32 slotCount
)
672 Slot
* slots
= mapBlockToVtable(block
);
675 return slots
+ slotCount
;
678 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
679 Slot
** slots
, unsigned char * code
,
680 typelib_InterfaceTypeDescription
const * type
, sal_Int32 functionOffset
,
681 sal_Int32 functionCount
, sal_Int32 vtableOffset
)
683 (*slots
) -= functionCount
;
686 // fprintf(stderr, "in addLocalFunctions functionOffset is %x\n",functionOffset);
687 // fprintf(stderr, "in addLocalFunctions vtableOffset is %x\n",vtableOffset);
690 for (sal_Int32 i
= 0; i
< type
->nMembers
; ++i
) {
691 typelib_TypeDescription
* member
= 0;
692 TYPELIB_DANGER_GET(&member
, type
->ppMembers
[i
]);
693 OSL_ASSERT(member
!= 0);
694 switch (member
->eTypeClass
) {
695 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
699 code
, functionOffset
++, vtableOffset
,
700 bridges::cpp_uno::shared::isSimpleType(
702 typelib_InterfaceAttributeTypeDescription
* >(
703 member
)->pAttributeTypeRef
));
706 if (!reinterpret_cast<
707 typelib_InterfaceAttributeTypeDescription
* >(
711 code
= codeSnippet(code
, functionOffset
++, vtableOffset
, true);
715 case typelib_TypeClass_INTERFACE_METHOD
:
718 code
, functionOffset
++, vtableOffset
,
719 bridges::cpp_uno::shared::isSimpleType(
721 typelib_InterfaceMethodTypeDescription
* >(
722 member
)->pReturnTypeRef
));
729 TYPELIB_DANGER_RELEASE(member
);