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"
33 #include <com/sun/star/uno/genfunc.hxx>
34 #include <typelib/typedescription.hxx>
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"
42 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
,
53 sal_Int64
* pRegisterReturn
/* space for register return */ )
55 // pCallStack: [ret ptr], this, params
56 char * pCppStack
= (char *)pCallStack
;
59 typelib_TypeDescription
* pReturnTypeDescr
= 0;
61 TYPELIB_DANGER_GET( &pReturnTypeDescr
, pReturnTypeRef
);
63 void * pUnoReturn
= 0;
64 void * pCppReturn
= 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
68 if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr
))
69 pUnoReturn
= pRegisterReturn
; // direct way for simple types
70 else // complex return via ptr (pCppReturn)
72 pCppReturn
= *(void**)pCppStack
;
73 pUnoReturn
= (bridges::cpp_uno::shared::relatesToInterfaceType(
75 ? alloca( pReturnTypeDescr
->nSize
)
76 : pCppReturn
); // direct way
77 pCppStack
+= sizeof( void* );
81 pCppStack
+= sizeof( void* );
84 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32
), "### unexpected size!" );
86 void ** pUnoArgs
= (void **)alloca( 4 * sizeof(void *) * nParams
);
87 void ** pCppArgs
= pUnoArgs
+ nParams
;
88 // indizes of values this have to be converted (interface conversion cpp<=>uno)
89 sal_Int32
* pTempIndizes
= (sal_Int32
*)(pUnoArgs
+ (2 * nParams
));
90 // type descriptions for reconversions
91 typelib_TypeDescription
** ppTempParamTypeDescr
= (typelib_TypeDescription
**)(pUnoArgs
+ (3 * nParams
));
93 sal_Int32 nTempIndizes
= 0;
95 for ( sal_Int32 nPos
= 0; nPos
< nParams
; ++nPos
)
97 const typelib_MethodParameter
& rParam
= pParams
[nPos
];
98 typelib_TypeDescription
* pParamTypeDescr
= 0;
99 TYPELIB_DANGER_GET( &pParamTypeDescr
, rParam
.pTypeRef
);
101 if (!rParam
.bOut
&& bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr
)) // value
103 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = CPPU_CURRENT_NAMESPACE::adjustPointer(pCppStack
, pParamTypeDescr
);
104 switch (pParamTypeDescr
->eTypeClass
)
106 case typelib_TypeClass_HYPER
:
107 case typelib_TypeClass_UNSIGNED_HYPER
:
108 case typelib_TypeClass_DOUBLE
:
110 if ((reinterpret_cast< long >(pCppStack
) & 7) != 0)
112 OSL_ASSERT( sizeof (double) == sizeof (sal_Int64
) );
113 void * pDest
= alloca( sizeof (sal_Int64
) );
114 *reinterpret_cast< sal_Int32
* >(pDest
) =
115 *reinterpret_cast< sal_Int32
const * >(pCppStack
);
116 *(reinterpret_cast< sal_Int32
* >(pDest
) + 1) =
117 *(reinterpret_cast< sal_Int32
const * >(pCppStack
) + 1);
118 pCppArgs
[nPos
] = pUnoArgs
[nPos
] = pDest
;
120 pCppStack
+= sizeof (sal_Int32
); // extra long
127 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
129 else // ptr to complex value | ref
131 pCppArgs
[nPos
] = *(void **)pCppStack
;
133 if (! rParam
.bIn
) // is pure out
135 // uno out is unconstructed mem!
136 pUnoArgs
[nPos
] = alloca( pParamTypeDescr
->nSize
);
137 pTempIndizes
[nTempIndizes
] = nPos
;
138 // will be released at reconversion
139 ppTempParamTypeDescr
[nTempIndizes
++] = pParamTypeDescr
;
142 else if (bridges::cpp_uno::shared::relatesToInterfaceType(
145 uno_copyAndConvertData( pUnoArgs
[nPos
] = alloca( pParamTypeDescr
->nSize
),
146 *(void **)pCppStack
, pParamTypeDescr
,
147 pThis
->getBridge()->getCpp2Uno() );
148 pTempIndizes
[nTempIndizes
] = nPos
; // has to be reconverted
149 // will be released at reconversion
150 ppTempParamTypeDescr
[nTempIndizes
++] = pParamTypeDescr
;
154 pUnoArgs
[nPos
] = *(void **)pCppStack
;
156 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
159 pCppStack
+= sizeof(sal_Int32
); // standard parameter length
163 uno_Any aUnoExc
; // Any will be constructed by callee
164 uno_Any
* pUnoExc
= &aUnoExc
;
166 // invoke uno dispatch call
167 (*pThis
->getUnoI()->pDispatcher
)(pThis
->getUnoI(), pMemberTypeDescr
, pUnoReturn
, pUnoArgs
, &pUnoExc
);
169 // in case an exception occured...
172 // destruct temporary in/inout params
173 for ( ; nTempIndizes
--; )
175 sal_Int32 nIndex
= pTempIndizes
[nTempIndizes
];
177 if (pParams
[nIndex
].bIn
) // is in/inout => was constructed
178 uno_destructData( pUnoArgs
[nIndex
], ppTempParamTypeDescr
[nTempIndizes
], 0 );
179 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr
[nTempIndizes
] );
181 if (pReturnTypeDescr
)
182 TYPELIB_DANGER_RELEASE( pReturnTypeDescr
);
183 CPPU_CURRENT_NAMESPACE::raiseException(&aUnoExc
, pThis
->getBridge()->getUno2Cpp() );
184 // has to destruct the any
186 return typelib_TypeClass_VOID
;
188 else // else no exception occured...
191 for ( ; nTempIndizes
--; )
193 sal_Int32 nIndex
= pTempIndizes
[nTempIndizes
];
194 typelib_TypeDescription
* pParamTypeDescr
= ppTempParamTypeDescr
[nTempIndizes
];
196 if (pParams
[nIndex
].bOut
) // inout/out
198 // convert and assign
199 uno_destructData( pCppArgs
[nIndex
], pParamTypeDescr
, cpp_release
);
200 uno_copyAndConvertData( pCppArgs
[nIndex
], pUnoArgs
[nIndex
], pParamTypeDescr
,
201 pThis
->getBridge()->getUno2Cpp() );
203 // destroy temp uno param
204 uno_destructData( pUnoArgs
[nIndex
], pParamTypeDescr
, 0 );
206 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
209 if (pCppReturn
) // has complex return
211 if (pUnoReturn
!= pCppReturn
) // needs reconversion
213 uno_copyAndConvertData( pCppReturn
, pUnoReturn
, pReturnTypeDescr
,
214 pThis
->getBridge()->getUno2Cpp() );
215 // destroy temp uno return
216 uno_destructData( pUnoReturn
, pReturnTypeDescr
, 0 );
218 // complex return ptr is set to eax
219 *(void **)pRegisterReturn
= pCppReturn
;
221 if (pReturnTypeDescr
)
223 typelib_TypeClass eRet
= (typelib_TypeClass
)pReturnTypeDescr
->eTypeClass
;
224 TYPELIB_DANGER_RELEASE( pReturnTypeDescr
);
228 return typelib_TypeClass_VOID
;
233 //==================================================================================================
234 static typelib_TypeClass
cpp_mediate(
235 sal_Int32 nFunctionIndex
,
236 sal_Int32 nVtableOffset
,
238 sal_Int64
* pRegisterReturn
/* space for register return */ )
240 OSL_ENSURE( sizeof(sal_Int32
)==sizeof(void *), "### unexpected!" );
242 // pCallStack: this, params
243 // eventual [ret*] lies at pCallStack -1
244 // so count down pCallStack by one to keep it simple
245 // pCallStack: this, params
246 // eventual [ret*] lies at pCallStack -1
247 // so count down pCallStack by one to keep it simple
248 bridges::cpp_uno::shared::CppInterfaceProxy
* pCppI
249 = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
250 static_cast< char * >(*pCallStack
) - nVtableOffset
);
251 if ((nFunctionIndex
& 0x80000000) != 0) {
252 nFunctionIndex
&= 0x7FFFFFFF;
256 typelib_InterfaceTypeDescription
* pTypeDescr
= pCppI
->getTypeDescr();
258 OSL_ENSURE( nFunctionIndex
< pTypeDescr
->nMapFunctionIndexToMemberIndex
,
259 "### illegal vtable index!" );
260 if (nFunctionIndex
>= pTypeDescr
->nMapFunctionIndexToMemberIndex
)
262 throw RuntimeException( rtl::OUString::createFromAscii("illegal vtable index!"), (XInterface
*)pCppI
);
265 // determine called method
266 sal_Int32 nMemberPos
= pTypeDescr
->pMapFunctionIndexToMemberIndex
[nFunctionIndex
];
267 OSL_ENSURE( nMemberPos
< pTypeDescr
->nAllMembers
, "### illegal member index!" );
269 TypeDescription
aMemberDescr( pTypeDescr
->ppAllMembers
[nMemberPos
] );
271 #if defined BRIDGES_DEBUG
272 OString
cstr( OUStringToOString( aMemberDescr
.get()->pTypeName
, RTL_TEXTENCODING_ASCII_US
) );
273 fprintf( stderr
, "calling %s, nFunctionIndex=%d\n", cstr
.getStr(), nFunctionIndex
);
276 typelib_TypeClass eRet
;
277 switch (aMemberDescr
.get()->eTypeClass
)
279 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
281 if (pTypeDescr
->pMapMemberIndexToFunctionIndex
[nMemberPos
] == nFunctionIndex
)
285 pCppI
, aMemberDescr
.get(),
286 ((typelib_InterfaceAttributeTypeDescription
*)aMemberDescr
.get())->pAttributeTypeRef
,
288 pCallStack
, pRegisterReturn
);
293 typelib_MethodParameter aParam
;
295 ((typelib_InterfaceAttributeTypeDescription
*)aMemberDescr
.get())->pAttributeTypeRef
;
296 aParam
.bIn
= sal_True
;
297 aParam
.bOut
= sal_False
;
300 pCppI
, aMemberDescr
.get(),
301 0, // indicates void return
303 pCallStack
, pRegisterReturn
);
307 case typelib_TypeClass_INTERFACE_METHOD
:
310 switch (nFunctionIndex
)
313 pCppI
->acquireProxy(); // non virtual call!
314 eRet
= typelib_TypeClass_VOID
;
317 pCppI
->releaseProxy(); // non virtual call!
318 eRet
= typelib_TypeClass_VOID
;
320 case 0: // queryInterface() opt
322 typelib_TypeDescription
* pTD
= 0;
323 TYPELIB_DANGER_GET( &pTD
, reinterpret_cast< Type
* >( pCallStack
[2] )->getTypeLibType() );
326 XInterface
* pInterface
= 0;
327 (*pCppI
->getBridge()->getCppEnv()->getRegisteredInterface
)(
328 pCppI
->getBridge()->getCppEnv(),
329 (void **)&pInterface
, pCppI
->getOid().pData
, (typelib_InterfaceTypeDescription
*)pTD
);
334 reinterpret_cast< uno_Any
* >( pCallStack
[0] ),
335 &pInterface
, pTD
, cpp_acquire
);
336 pInterface
->release();
337 TYPELIB_DANGER_RELEASE( pTD
);
338 *(void **)pRegisterReturn
= pCallStack
[0];
339 eRet
= typelib_TypeClass_ANY
;
342 TYPELIB_DANGER_RELEASE( pTD
);
344 } // else perform queryInterface()
347 pCppI
, aMemberDescr
.get(),
348 ((typelib_InterfaceMethodTypeDescription
*)aMemberDescr
.get())->pReturnTypeRef
,
349 ((typelib_InterfaceMethodTypeDescription
*)aMemberDescr
.get())->nParams
,
350 ((typelib_InterfaceMethodTypeDescription
*)aMemberDescr
.get())->pParams
,
351 pCallStack
, pRegisterReturn
);
357 throw RuntimeException(rtl::OUString::createFromAscii("no member description found!"), (XInterface
*)pCppI
);
359 eRet
= typelib_TypeClass_VOID
;
367 //==================================================================================================
369 * is called on incoming vtable calls
370 * (called by asm snippets)
372 static void cpp_vtable_call()
374 sal_Int64 nRegReturn
;
379 void * pRegReturn
= &nRegReturn
;
381 __asm__( "st %%i0, %0\n\t"
384 : : "m"(nFunctionIndex
), "m"(pCallStack
), "m"(vTableOffset
) );
386 // fprintf(stderr,"cpp_mediate nFunctionIndex=%x\n",nFunctionIndex);
389 sal_Bool bComplex
= nFunctionIndex
& 0x80000000 ? sal_True
: sal_False
;
390 typelib_TypeClass aType
=
391 cpp_mediate( nFunctionIndex
, vTableOffset
, pCallStack
+17, (sal_Int64
*)&nRegReturn
);
395 case typelib_TypeClass_BOOLEAN
:
396 case typelib_TypeClass_BYTE
:
397 __asm__( "ld %0, %%l0\n\t"
398 "ldsb [%%l0], %%i0\n"
399 : : "m"(pRegReturn
) );
401 case typelib_TypeClass_CHAR
:
402 case typelib_TypeClass_SHORT
:
403 case typelib_TypeClass_UNSIGNED_SHORT
:
404 __asm__( "ld %0, %%l0\n\t"
405 "ldsh [%%l0], %%i0\n"
406 : : "m"(pRegReturn
) );
408 case typelib_TypeClass_HYPER
:
409 case typelib_TypeClass_UNSIGNED_HYPER
:
410 __asm__( "ld %0, %%l0\n\t"
411 "ld [%%l0], %%i0\n\t"
412 "add %%l0, 4, %%l0\n\t"
413 "ld [%%l0], %%i1\n\t"
414 : : "m"(pRegReturn
) );
417 case typelib_TypeClass_FLOAT
:
418 __asm__( "ld %0, %%l0\n\t"
420 : : "m"(pRegReturn
) );
422 case typelib_TypeClass_DOUBLE
:
423 __asm__( "ld %0, %%l0\n\t"
425 : : "m"(pRegReturn
) );
427 case typelib_TypeClass_VOID
:
430 __asm__( "ld %0, %%l0\n\t"
432 : : "m"(pRegReturn
) );
438 __asm__( "add %i7, 4, %i7\n\t" );
439 // after call to complex return valued funcion there is an unimp instruction
443 //__________________________________________________________________________________________________
445 int const codeSnippetSize
= 56;
446 unsigned char * codeSnippet(
447 unsigned char * code
, sal_Int32 functionIndex
, sal_Int32 vtableOffset
,
450 sal_uInt32 index
= functionIndex
;
451 if (!simpleRetType
) {
454 unsigned int * p
= reinterpret_cast< unsigned int * >(code
);
455 OSL_ASSERT(sizeof (unsigned int) == 4);
468 // sethi %hi(index), %o0:
469 *p
++ = 0x11000000 | (index
>> 10);
470 // or %o0, %lo(index), %o0:
471 *p
++ = 0x90122000 | (index
& 0x3FF);
472 // sethi %hi(vtableOffset), %o2:
473 *p
++ = 0x15000000 | (vtableOffset
>> 10);
474 // or %o2, %lo(vtableOffset), %o2:
475 *p
++ = 0x9412A000 | (vtableOffset
& 0x3FF);
476 // sethi %hi(cpp_vtable_call), %o3:
477 *p
++ = 0x17000000 | (reinterpret_cast< unsigned int >(cpp_vtable_call
) >> 10);
478 // or %o3, %lo(cpp_vtable_call), %o3:
479 *p
++ = 0x9612E000 | (reinterpret_cast< unsigned int >(cpp_vtable_call
) & 0x3FF);
485 reinterpret_cast< unsigned char * >(p
) - code
<= codeSnippetSize
);
486 return code
+ codeSnippetSize
;
491 struct bridges::cpp_uno::shared::VtableFactory::Slot
{ void * fn
; };
493 bridges::cpp_uno::shared::VtableFactory::Slot
*
494 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block
)
496 return static_cast< Slot
* >(block
) + 2;
499 sal_Size
bridges::cpp_uno::shared::VtableFactory::getBlockSize(
502 return (slotCount
+ 2) * sizeof (Slot
) + slotCount
* codeSnippetSize
;
505 bridges::cpp_uno::shared::VtableFactory::Slot
*
506 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
507 void * block
, sal_Int32 slotCount
)
509 Slot
* slots
= mapBlockToVtable(block
);
510 slots
[-2].fn
= 0; //null
511 slots
[-1].fn
= 0; //destructor
512 return slots
+ slotCount
;
515 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
516 Slot
** slots
, unsigned char * code
, sal_PtrDiff writetoexecdiff
,
517 typelib_InterfaceTypeDescription
const * type
, sal_Int32 functionOffset
,
518 sal_Int32 functionCount
, sal_Int32 vTableOffset
)
520 (*slots
) -= functionCount
;
522 for (sal_Int32 i
= 0; i
< type
->nMembers
; ++i
) {
523 typelib_TypeDescription
* member
= 0;
524 TYPELIB_DANGER_GET(&member
, type
->ppMembers
[i
]);
525 OSL_ASSERT(member
!= 0);
526 switch (member
->eTypeClass
) {
527 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
529 (s
++)->fn
= code
+ writetoexecdiff
;
531 code
, functionOffset
++, vTableOffset
,
532 bridges::cpp_uno::shared::isSimpleType(
534 typelib_InterfaceAttributeTypeDescription
* >(
535 member
)->pAttributeTypeRef
));
537 if (!reinterpret_cast<
538 typelib_InterfaceAttributeTypeDescription
* >(
541 (s
++)->fn
= code
+ writetoexecdiff
;
542 code
= codeSnippet(code
, functionOffset
++, vTableOffset
, true);
546 case typelib_TypeClass_INTERFACE_METHOD
:
547 (s
++)->fn
= code
+ writetoexecdiff
;
549 code
, functionOffset
++, vTableOffset
,
550 bridges::cpp_uno::shared::isSimpleType(
552 typelib_InterfaceMethodTypeDescription
* >(
553 member
)->pReturnTypeRef
));
560 TYPELIB_DANGER_RELEASE(member
);
565 // use flush code from cc50_solaris_sparc
567 extern "C" void doFlushCode(unsigned long address
, unsigned long count
);
569 void bridges::cpp_uno::shared::VtableFactory::flushCode(
570 unsigned char const * begin
, unsigned char const * end
)
572 unsigned long n
= end
- begin
;
574 unsigned long adr
= reinterpret_cast< unsigned long >(begin
);
575 unsigned long off
= adr
& 7;
576 doFlushCode(adr
- off
, (n
+ off
+ 7) >> 3);