1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include <com/sun/star/uno/genfunc.hxx>
32 #include <typelib/typedescription.hxx>
34 #include "bridges/cpp_uno/shared/bridge.hxx"
35 #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx"
36 #include "bridges/cpp_uno/shared/types.hxx"
37 #include "bridges/cpp_uno/shared/vtablefactory.hxx"
41 using namespace ::com::sun::star::uno
;
46 //==================================================================================================
47 static typelib_TypeClass
cpp2uno_call(
48 bridges::cpp_uno::shared::CppInterfaceProxy
* pThis
,
49 const typelib_TypeDescription
* pMemberTypeDescr
,
50 typelib_TypeDescriptionReference
* pReturnTypeRef
, // 0 indicates void return
51 sal_Int32 nParams
, typelib_MethodParameter
* pParams
,
52 void ** gpreg
, void ** fpreg
, void ** ovrflw
,
53 sal_Int64
* pRegisterReturn
/* space for register return */ )
56 // gpreg: [ret *], this, [gpr params]
57 // fpreg: [fpr params]
58 // ovrflw: [gpr or fpr params (space for entire parameter list in structure format properly aligned)]
61 typelib_TypeDescription
* pReturnTypeDescr
= 0;
63 TYPELIB_DANGER_GET( &pReturnTypeDescr
, pReturnTypeRef
);
65 void * pUnoReturn
= 0;
66 void * pCppReturn
= 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
74 if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr
))
75 pUnoReturn
= pRegisterReturn
; // direct way for simple types
76 else // complex return via ptr (pCppReturn)
82 pUnoReturn
= (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr
)
83 ? alloca( pReturnTypeDescr
->nSize
)
84 : pCppReturn
); // direct way
91 // after handling optional return pointer and "this"
92 // make use of the space that is allocated to store all parameters in the callers stack
93 // by comying the proper registers filled with parameters to that space
94 char * pCppStack
= (char *)ovrflw
;
99 for ( nPos
= 0; nPos
< nParams
; ++nPos
)
101 const typelib_MethodParameter
& rParam
= pParams
[nPos
];
106 *(sal_Int32
*)pCppStack
= ((sal_Int32
*)gpreg
)[ngpreg
++];
108 pCppStack
+= sizeof (sal_Int32
);
112 switch (rParam
.pTypeRef
->eTypeClass
)
114 case typelib_TypeClass_FLOAT
:
117 *(float *)pCppStack
= ((double *)fpreg
)[nfpreg
++];
119 pCppStack
+= sizeof (float);
122 case typelib_TypeClass_DOUBLE
:
125 *(double *)pCppStack
= ((double *)fpreg
)[nfpreg
++];
127 pCppStack
+= sizeof (double);
130 case typelib_TypeClass_UNSIGNED_HYPER
:
131 case typelib_TypeClass_HYPER
:
134 *(sal_Int32
*)pCppStack
= ((sal_Int32
*)gpreg
)[ngpreg
++];
136 pCppStack
+= sizeof (sal_Int32
);
137 // fall through on purpose
141 *(sal_Int32
*)pCppStack
= ((sal_Int32
*)gpreg
)[ngpreg
++];
143 pCppStack
+= sizeof (sal_Int32
);
148 // now the stack has all of the parameters stored in it ready to be processed
149 // so we are ready to build the uno call stack
150 pCppStack
= (char *)ovrflw
;
153 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32
), "### unexpected size!" );
156 void ** pUnoArgs
= (void **)alloca( 4 * sizeof(void *) * nParams
);
157 void ** pCppArgs
= pUnoArgs
+ nParams
;
159 // indizes of values this have to be converted (interface conversion cpp<=>uno)
160 sal_Int32
* pTempIndizes
= (sal_Int32
*)(pUnoArgs
+ (2 * nParams
));
162 // type descriptions for reconversions
163 typelib_TypeDescription
** ppTempParamTypeDescr
= (typelib_TypeDescription
**)(pUnoArgs
+ (3 * nParams
));
165 sal_Int32 nTempIndizes
= 0;
167 for ( nPos
= 0; nPos
< nParams
; ++nPos
)
169 const typelib_MethodParameter
& rParam
= pParams
[nPos
];
170 typelib_TypeDescription
* pParamTypeDescr
= 0;
171 TYPELIB_DANGER_GET( &pParamTypeDescr
, rParam
.pTypeRef
);
173 if (!rParam
.bOut
&& bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr
))
176 switch (pParamTypeDescr
->eTypeClass
)
178 case typelib_TypeClass_BOOLEAN
:
179 case typelib_TypeClass_BYTE
:
180 pCppArgs
[nPos
] = pCppStack
+3;
181 pUnoArgs
[nPos
] = pCppStack
+3;
183 case typelib_TypeClass_CHAR
:
184 case typelib_TypeClass_SHORT
:
185 case typelib_TypeClass_UNSIGNED_SHORT
:
186 pCppArgs
[nPos
] = pCppStack
+2;
187 pUnoArgs
[nPos
] = pCppStack
+2;
189 case typelib_TypeClass_HYPER
:
190 case typelib_TypeClass_UNSIGNED_HYPER
:
191 case typelib_TypeClass_DOUBLE
:
192 pCppArgs
[nPos
] = pCppStack
;
193 pUnoArgs
[nPos
] = pCppStack
;
194 pCppStack
+= sizeof(sal_Int32
); // extra long (two regs)
197 pCppArgs
[nPos
] = pCppStack
;
198 pUnoArgs
[nPos
] = pCppStack
;
201 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
203 else // ptr to complex value | ref
205 pCppArgs
[nPos
] = *(void **)pCppStack
;
207 if (! rParam
.bIn
) // is pure out
209 // uno out is unconstructed mem!
210 pUnoArgs
[nPos
] = alloca( pParamTypeDescr
->nSize
);
211 pTempIndizes
[nTempIndizes
] = nPos
;
212 // will be released at reconversion
213 ppTempParamTypeDescr
[nTempIndizes
++] = pParamTypeDescr
;
216 else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr
))
218 uno_copyAndConvertData( pUnoArgs
[nPos
] = alloca( pParamTypeDescr
->nSize
),
219 *(void **)pCppStack
, pParamTypeDescr
,
220 pThis
->getBridge()->getCpp2Uno() );
221 pTempIndizes
[nTempIndizes
] = nPos
; // has to be reconverted
222 // will be released at reconversion
223 ppTempParamTypeDescr
[nTempIndizes
++] = pParamTypeDescr
;
227 pUnoArgs
[nPos
] = *(void **)pCppStack
;
229 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
232 pCppStack
+= sizeof(sal_Int32
); // standard parameter length
237 uno_Any aUnoExc
; // Any will be constructed by callee
238 uno_Any
* pUnoExc
= &aUnoExc
;
240 // invoke uno dispatch call
241 (*pThis
->getUnoI()->pDispatcher
)(
242 pThis
->getUnoI(), pMemberTypeDescr
, pUnoReturn
, pUnoArgs
, &pUnoExc
);
244 // in case an exception occurred...
247 // destruct temporary in/inout params
248 for ( ; nTempIndizes
--; )
250 sal_Int32 nIndex
= pTempIndizes
[nTempIndizes
];
252 if (pParams
[nIndex
].bIn
) // is in/inout => was constructed
253 uno_destructData( pUnoArgs
[nIndex
], ppTempParamTypeDescr
[nTempIndizes
], 0 );
254 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr
[nTempIndizes
] );
256 if (pReturnTypeDescr
)
257 TYPELIB_DANGER_RELEASE( pReturnTypeDescr
);
259 CPPU_CURRENT_NAMESPACE::raiseException(
260 &aUnoExc
, pThis
->getBridge()->getUno2Cpp() );
261 // has to destruct the any
263 return typelib_TypeClass_VOID
;
265 else // else no exception occurred...
268 for ( ; nTempIndizes
--; )
270 sal_Int32 nIndex
= pTempIndizes
[nTempIndizes
];
271 typelib_TypeDescription
* pParamTypeDescr
= ppTempParamTypeDescr
[nTempIndizes
];
273 if (pParams
[nIndex
].bOut
) // inout/out
275 // convert and assign
276 uno_destructData( pCppArgs
[nIndex
], pParamTypeDescr
, cpp_release
);
277 uno_copyAndConvertData( pCppArgs
[nIndex
], pUnoArgs
[nIndex
], pParamTypeDescr
,
278 pThis
->getBridge()->getUno2Cpp() );
280 // destroy temp uno param
281 uno_destructData( pUnoArgs
[nIndex
], pParamTypeDescr
, 0 );
283 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
286 if (pCppReturn
) // has complex return
288 if (pUnoReturn
!= pCppReturn
) // needs reconversion
290 uno_copyAndConvertData( pCppReturn
, pUnoReturn
, pReturnTypeDescr
,
291 pThis
->getBridge()->getUno2Cpp() );
292 // destroy temp uno return
293 uno_destructData( pUnoReturn
, pReturnTypeDescr
, 0 );
295 // complex return ptr is set to return reg
296 *(void **)pRegisterReturn
= pCppReturn
;
298 if (pReturnTypeDescr
)
300 typelib_TypeClass eRet
= (typelib_TypeClass
)pReturnTypeDescr
->eTypeClass
;
301 TYPELIB_DANGER_RELEASE( pReturnTypeDescr
);
305 return typelib_TypeClass_VOID
;
310 //==================================================================================================
311 static typelib_TypeClass
cpp_mediate(
312 sal_Int32 nFunctionIndex
,
313 sal_Int32 nVtableOffset
,
314 void ** gpreg
, void ** fpreg
, void ** ovrflw
,
315 sal_Int64
* pRegisterReturn
/* space for register return */ )
317 OSL_ENSURE( sizeof(sal_Int32
)==sizeof(void *), "### unexpected!" );
319 // gpreg: [ret *], this, [other gpr params]
320 // fpreg: [fpr params]
321 // ovrflw: [gpr or fpr params (in space allocated for all params properly aligned)]
324 if( nFunctionIndex
& 0x80000000 )
326 nFunctionIndex
&= 0x7fffffff;
334 pThis
= static_cast< char * >(pThis
) - nVtableOffset
;
335 bridges::cpp_uno::shared::CppInterfaceProxy
* pCppI
336 = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(pThis
);
339 typelib_InterfaceTypeDescription
* pTypeDescr
= pCppI
->getTypeDescr();
341 OSL_ENSURE( nFunctionIndex
< pTypeDescr
->nMapFunctionIndexToMemberIndex
, "### illegal vtable index!" );
342 if (nFunctionIndex
>= pTypeDescr
->nMapFunctionIndexToMemberIndex
)
344 throw RuntimeException(
345 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "illegal vtable index!" )),
346 (XInterface
*)pThis
);
349 // determine called method
350 sal_Int32 nMemberPos
= pTypeDescr
->pMapFunctionIndexToMemberIndex
[nFunctionIndex
];
351 OSL_ENSURE( nMemberPos
< pTypeDescr
->nAllMembers
, "### illegal member index!" );
353 TypeDescription
aMemberDescr( pTypeDescr
->ppAllMembers
[nMemberPos
] );
355 typelib_TypeClass eRet
;
356 switch (aMemberDescr
.get()->eTypeClass
)
358 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
360 if (pTypeDescr
->pMapMemberIndexToFunctionIndex
[nMemberPos
] == nFunctionIndex
)
364 pCppI
, aMemberDescr
.get(),
365 ((typelib_InterfaceAttributeTypeDescription
*)aMemberDescr
.get())->pAttributeTypeRef
,
367 gpreg
, fpreg
, ovrflw
, pRegisterReturn
);
372 typelib_MethodParameter aParam
;
374 ((typelib_InterfaceAttributeTypeDescription
*)aMemberDescr
.get())->pAttributeTypeRef
;
375 aParam
.bIn
= sal_True
;
376 aParam
.bOut
= sal_False
;
379 pCppI
, aMemberDescr
.get(),
380 0, // indicates void return
382 gpreg
, fpreg
, ovrflw
, pRegisterReturn
);
386 case typelib_TypeClass_INTERFACE_METHOD
:
389 switch (nFunctionIndex
)
392 pCppI
->acquireProxy(); // non virtual call!
393 eRet
= typelib_TypeClass_VOID
;
396 pCppI
->releaseProxy(); // non virtual call!
397 eRet
= typelib_TypeClass_VOID
;
399 case 0: // queryInterface() opt
401 typelib_TypeDescription
* pTD
= 0;
402 TYPELIB_DANGER_GET( &pTD
, reinterpret_cast< Type
* >( gpreg
[2] )->getTypeLibType() );
405 XInterface
* pInterface
= 0;
406 (*pCppI
->getBridge()->getCppEnv()->getRegisteredInterface
)(
407 pCppI
->getBridge()->getCppEnv(),
408 (void **)&pInterface
, pCppI
->getOid().pData
, (typelib_InterfaceTypeDescription
*)pTD
);
413 reinterpret_cast< uno_Any
* >( gpreg
[0] ),
414 &pInterface
, pTD
, cpp_acquire
);
415 pInterface
->release();
416 TYPELIB_DANGER_RELEASE( pTD
);
417 *(void **)pRegisterReturn
= gpreg
[0];
418 eRet
= typelib_TypeClass_ANY
;
421 TYPELIB_DANGER_RELEASE( pTD
);
423 } // else perform queryInterface()
426 pCppI
, aMemberDescr
.get(),
427 ((typelib_InterfaceMethodTypeDescription
*)aMemberDescr
.get())->pReturnTypeRef
,
428 ((typelib_InterfaceMethodTypeDescription
*)aMemberDescr
.get())->nParams
,
429 ((typelib_InterfaceMethodTypeDescription
*)aMemberDescr
.get())->pParams
,
430 gpreg
, fpreg
, ovrflw
, pRegisterReturn
);
436 throw RuntimeException(
437 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "no member description found!" )),
438 (XInterface
*)pThis
);
445 //==================================================================================================
447 * is called on incoming vtable calls
448 * (called by asm snippets)
450 static void cpp_vtable_call( int nFunctionIndex
, int nVtableOffset
, void** gpregptr
, void** fpregptr
, void** ovrflw
)
455 // FIXME: why are we restoring the volatile ctr register here
456 sal_Int32 ctrsave
= ((sal_Int32
*)gpregptr
)[-1];
458 memcpy( gpreg
, gpregptr
, 32);
459 memcpy( fpreg
, fpregptr
, 104);
461 volatile long nRegReturn
[2];
463 // sal_Bool bComplex = nFunctionIndex & 0x80000000 ? sal_True : sal_False;
465 typelib_TypeClass aType
=
466 cpp_mediate( nFunctionIndex
, nVtableOffset
, (void**)gpreg
, (void**)fpreg
, ovrflw
, (sal_Int64
*)nRegReturn
);
468 // FIXME: why are we restoring the volatile ctr register here
469 // FIXME: and why are we putting back the values for r4, r5, and r6 as well
470 // FIXME: this makes no sense to me, all of these registers are volatile!
471 __asm__( "lwz r4, %0\n\t"
476 : : "m"(ctrsave
), "m"(gpreg
[1]), "m"(gpreg
[2]), "m"(gpreg
[3]) );
481 // move return value into register space
482 // (will be loaded by machine code snippet)
484 case typelib_TypeClass_BOOLEAN
:
485 case typelib_TypeClass_BYTE
:
486 __asm__( "lbz r3,%0\n\t" : :
487 "m"(nRegReturn
[0]) );
490 case typelib_TypeClass_CHAR
:
491 case typelib_TypeClass_SHORT
:
492 case typelib_TypeClass_UNSIGNED_SHORT
:
493 __asm__( "lhz r3,%0\n\t" : :
494 "m"(nRegReturn
[0]) );
497 case typelib_TypeClass_FLOAT
:
498 __asm__( "lfs f1,%0\n\t" : :
499 "m" (*((float*)nRegReturn
)) );
502 case typelib_TypeClass_DOUBLE
:
503 __asm__( "lfd f1,%0\n\t" : :
504 "m" (*((double*)nRegReturn
)) );
507 case typelib_TypeClass_HYPER
:
508 case typelib_TypeClass_UNSIGNED_HYPER
:
509 __asm__( "lwz r4,%0\n\t" : :
510 "m"(nRegReturn
[1]) ); // fall through
513 __asm__( "lwz r3,%0\n\t" : :
514 "m"(nRegReturn
[0]) );
520 int const codeSnippetSize
= 136;
522 unsigned char * codeSnippet( unsigned char * code
, sal_Int32 functionIndex
,
523 sal_Int32 vtableOffset
, bool simpleRetType
)
525 if (! simpleRetType
)
526 functionIndex
|= 0x80000000;
528 // OSL_ASSERT( sizeof (long) == 4 );
530 // FIXME: why are we leaving an 8k gap in the stack here
531 // FIXME: is this to allow room for signal handling frames?
532 // FIXME: seems like overkill here but this is what was done for Mac OSX for gcc2
533 // FIXME: also why no saving of the non-volatile CR pieces here, to be safe
534 // FIXME: we probably should
536 /* generate this code */
538 // # so first save gpr 3 to gpr 10 (aligned to 4)
548 // # next save fpr 1 to fpr 13 (aligned to 8)
549 // stfd f1, -7968(r1)
550 // stfd f2, -7960(r1)
551 // stfd f3, -7952(r1)
552 // stfd f4, -7944(r1)
553 // stfd f5, -7936(r1)
554 // stfd f6, -7928(r1)
555 // stfd f7, -7920(r1)
556 // stfd f8, -7912(r1)
557 // stfd f9, -7904(r1)
558 // stfd f10,-7896(r1)
559 // stfd f11,-7888(r1)
560 // stfd f12,-7880(r1)
561 // stfd f13,-7872(r1)
563 // FIXME: ctr is volatile, while are we saving it and not CR?
567 // # now here is where cpp_vtable_call must go
572 // # now load up the functionIndex number
576 // # now load up the vtableOffset
580 // #now load up the pointer to the saved gpr registers
583 // #now load up the pointer to the saved fpr registers
586 // #now load up the pointer to the overflow call stack
587 // addi r7,r1,24 # frame pointer plus 24
591 unsigned long * p
= (unsigned long *) code
;
616 * p
++ = 0x3c600000 | (((unsigned long)cpp_vtable_call
) >> 16);
617 * p
++ = 0x60630000 | (((unsigned long)cpp_vtable_call
) & 0x0000FFFF);
619 * p
++ = 0x3c600000 | (((unsigned long)functionIndex
) >> 16);
620 * p
++ = 0x60630000 | (((unsigned long)functionIndex
) & 0x0000FFFF);
621 * p
++ = 0x3c800000 | (((unsigned long)vtableOffset
) >> 16);
622 * p
++ = 0x60840000 | (((unsigned long)vtableOffset
) & 0x0000FFFF);
628 return (code
+ codeSnippetSize
);
635 void bridges::cpp_uno::shared::VtableFactory::flushCode(unsigned char const * bptr
, unsigned char const * eptr
)
637 int const lineSize
= 32;
638 for (unsigned char const * p
= bptr
; p
< eptr
+ lineSize
; p
+= lineSize
) {
639 __asm__
volatile ("dcbst 0, %0" : : "r"(p
) : "memory");
641 __asm__
volatile ("sync" : : : "memory");
642 for (unsigned char const * p
= bptr
; p
< eptr
+ lineSize
; p
+= lineSize
) {
643 __asm__
volatile ("icbi 0, %0" : : "r"(p
) : "memory");
645 __asm__
volatile ("isync" : : : "memory");
648 struct bridges::cpp_uno::shared::VtableFactory::Slot
{ void * fn
; };
650 bridges::cpp_uno::shared::VtableFactory::Slot
*
651 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block
)
653 return static_cast< Slot
* >(block
) + 2;
656 sal_Size
bridges::cpp_uno::shared::VtableFactory::getBlockSize(
659 return (slotCount
+ 2) * sizeof (Slot
) + slotCount
* codeSnippetSize
;
662 bridges::cpp_uno::shared::VtableFactory::Slot
*
663 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
664 void * block
, sal_Int32 slotCount
)
666 Slot
* slots
= mapBlockToVtable(block
);
669 return slots
+ slotCount
;
672 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
673 Slot
** slots
, unsigned char * code
,
674 typelib_InterfaceTypeDescription
const * type
, sal_Int32 functionOffset
,
675 sal_Int32 functionCount
, sal_Int32 vtableOffset
)
677 (*slots
) -= functionCount
;
680 // fprintf(stderr, "in addLocalFunctions functionOffset is %x\n",functionOffset);
681 // fprintf(stderr, "in addLocalFunctions vtableOffset is %x\n",vtableOffset);
684 for (sal_Int32 i
= 0; i
< type
->nMembers
; ++i
) {
685 typelib_TypeDescription
* member
= 0;
686 TYPELIB_DANGER_GET(&member
, type
->ppMembers
[i
]);
687 OSL_ASSERT(member
!= 0);
688 switch (member
->eTypeClass
) {
689 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
693 code
, functionOffset
++, vtableOffset
,
694 bridges::cpp_uno::shared::isSimpleType(
696 typelib_InterfaceAttributeTypeDescription
* >(
697 member
)->pAttributeTypeRef
));
700 if (!reinterpret_cast<
701 typelib_InterfaceAttributeTypeDescription
* >(
705 code
= codeSnippet(code
, functionOffset
++, vtableOffset
, true);
709 case typelib_TypeClass_INTERFACE_METHOD
:
712 code
, functionOffset
++, vtableOffset
,
713 bridges::cpp_uno::shared::isSimpleType(
715 typelib_InterfaceMethodTypeDescription
* >(
716 member
)->pReturnTypeRef
));
723 TYPELIB_DANGER_RELEASE(member
);
728 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */