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 ************************************************************************/
34 #include <rtl/alloc.h>
35 #include <osl/mutex.hxx>
37 #include <com/sun/star/uno/genfunc.hxx>
38 #include "com/sun/star/uno/RuntimeException.hpp"
40 #include <typelib/typedescription.hxx>
42 #include "bridges/cpp_uno/shared/bridge.hxx"
43 #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx"
44 #include "bridges/cpp_uno/shared/types.hxx"
45 #include "bridges/cpp_uno/shared/vtablefactory.hxx"
52 using namespace ::osl
;
53 using namespace ::rtl
;
54 using namespace ::com::sun::star::uno
;
59 static typelib_TypeClass
cpp2uno_call(
60 bridges::cpp_uno::shared::CppInterfaceProxy
* pThis
,
61 const typelib_TypeDescription
* pMemberTypeDescr
,
62 typelib_TypeDescriptionReference
* pReturnTypeRef
,
63 sal_Int32 nParams
, typelib_MethodParameter
* pParams
,
64 long r8
, void ** pCallStack
,
65 sal_Int64
* pRegisterReturn
/* space for register return */ )
67 // pCallStack: ret, [return ptr], this, params
68 char * pTopStack
= (char *)(pCallStack
+ 0);
69 char * pCppStack
= pTopStack
;
71 fprintf(stderr
, "cpp2uno_call\n");
74 typelib_TypeDescription
* pReturnTypeDescr
= 0;
76 TYPELIB_DANGER_GET( &pReturnTypeDescr
, pReturnTypeRef
);
78 void * pUnoReturn
= 0;
79 // complex return ptr: if != 0 && != pUnoReturn, reconversion need
80 void * pCppReturn
= 0;
84 if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr
))
87 fprintf(stderr
, "simple return\n");
89 pUnoReturn
= pRegisterReturn
; // direct way for simple types
91 else // complex return via ptr (pCppReturn)
94 fprintf(stderr
, "complex return\n");
96 pCppReturn
= (void *)r8
;
98 pUnoReturn
= (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr
)
99 ? alloca( pReturnTypeDescr
->nSize
)
100 : pCppReturn
); // direct way
104 pCppStack
+= sizeof( void* );
107 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32
),
108 "### unexpected size!" );
110 void ** pUnoArgs
= (void **)alloca( 4 * sizeof(void *) * nParams
);
111 void ** pCppArgs
= pUnoArgs
+ nParams
;
112 // indizes of values this have to be converted (interface conversion
114 sal_Int32
* pTempIndizes
= (sal_Int32
*)(pUnoArgs
+ (2 * nParams
));
115 // type descriptions for reconversions
116 typelib_TypeDescription
** ppTempParamTypeDescr
=
117 (typelib_TypeDescription
**)(pUnoArgs
+ (3 * nParams
));
119 sal_Int32 nTempIndizes
= 0;
121 for ( sal_Int32 nPos
= 0; nPos
< nParams
; ++nPos
)
123 const typelib_MethodParameter
& rParam
= pParams
[nPos
];
124 typelib_TypeDescription
* pParamTypeDescr
= 0;
125 TYPELIB_DANGER_GET( &pParamTypeDescr
, rParam
.pTypeRef
);
128 bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr
))
130 switch (pParamTypeDescr
->eTypeClass
)
132 case typelib_TypeClass_BYTE
:
133 case typelib_TypeClass_BOOLEAN
:
134 pCppArgs
[nPos
] = pCppStack
+ 3;
135 pUnoArgs
[nPos
] = pCppStack
+ 3;
137 case typelib_TypeClass_CHAR
:
138 case typelib_TypeClass_SHORT
:
139 case typelib_TypeClass_UNSIGNED_SHORT
:
140 pCppArgs
[nPos
] = pCppStack
+ 2;
141 pUnoArgs
[nPos
] = pCppStack
+ 2;
143 case typelib_TypeClass_HYPER
:
144 case typelib_TypeClass_UNSIGNED_HYPER
:
145 case typelib_TypeClass_DOUBLE
:
146 pCppArgs
[nPos
] = pCppStack
;
147 pUnoArgs
[nPos
] = pCppStack
;
148 pCppStack
+= sizeof(sal_Int32
); // extra long
151 pCppArgs
[nPos
] = pCppStack
;
152 pUnoArgs
[nPos
] = pCppStack
;
156 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
158 else // ptr to complex value | ref
160 pCppArgs
[nPos
] = *(void **)pCppStack
;
162 if (! rParam
.bIn
) // is pure out
164 // uno out is unconstructed mem!
165 pUnoArgs
[nPos
] = alloca( pParamTypeDescr
->nSize
);
166 pTempIndizes
[nTempIndizes
] = nPos
;
167 // will be released at reconversion
168 ppTempParamTypeDescr
[nTempIndizes
++] = pParamTypeDescr
;
171 else if (bridges::cpp_uno::shared::relatesToInterfaceType(
174 uno_copyAndConvertData( pUnoArgs
[nPos
] = alloca( pParamTypeDescr
->nSize
),
175 *(void **)pCppStack
, pParamTypeDescr
,
176 pThis
->getBridge()->getCpp2Uno() );
177 pTempIndizes
[nTempIndizes
] = nPos
; // has to be reconverted
178 // will be released at reconversion
179 ppTempParamTypeDescr
[nTempIndizes
++] = pParamTypeDescr
;
183 pUnoArgs
[nPos
] = *(void **)pCppStack
;
185 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
188 pCppStack
+= sizeof(sal_Int32
); // standard parameter length
192 uno_Any aUnoExc
; // Any will be constructed by callee
193 uno_Any
* pUnoExc
= &aUnoExc
;
196 fprintf(stderr
, "before dispatch\n");
198 // invoke uno dispatch call
199 (*pThis
->getUnoI()->pDispatcher
)(
200 pThis
->getUnoI(), pMemberTypeDescr
, pUnoReturn
, pUnoArgs
, &pUnoExc
);
203 fprintf(stderr
, "after dispatch\n");
206 // in case an exception occured...
209 // destruct temporary in/inout params
210 for ( ; nTempIndizes
--; )
212 sal_Int32 nIndex
= pTempIndizes
[nTempIndizes
];
214 if (pParams
[nIndex
].bIn
) // is in/inout => was constructed
215 uno_destructData( pUnoArgs
[nIndex
],
216 ppTempParamTypeDescr
[nTempIndizes
], 0 );
217 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr
[nTempIndizes
] );
219 if (pReturnTypeDescr
)
220 TYPELIB_DANGER_RELEASE( pReturnTypeDescr
);
222 CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc
,
223 pThis
->getBridge()->getUno2Cpp() ); // has to destruct the any
225 return typelib_TypeClass_VOID
;
227 else // else no exception occured...
230 for ( ; nTempIndizes
--; )
232 sal_Int32 nIndex
= pTempIndizes
[nTempIndizes
];
233 typelib_TypeDescription
* pParamTypeDescr
=
234 ppTempParamTypeDescr
[nTempIndizes
];
236 if (pParams
[nIndex
].bOut
) // inout/out
238 // convert and assign
239 uno_destructData( pCppArgs
[nIndex
], pParamTypeDescr
,
241 uno_copyAndConvertData( pCppArgs
[nIndex
], pUnoArgs
[nIndex
],
242 pParamTypeDescr
, pThis
->getBridge()->getUno2Cpp() );
244 // destroy temp uno param
245 uno_destructData( pUnoArgs
[nIndex
], pParamTypeDescr
, 0 );
247 TYPELIB_DANGER_RELEASE( pParamTypeDescr
);
250 if (pCppReturn
) // has complex return
252 if (pUnoReturn
!= pCppReturn
) // needs reconversion
254 uno_copyAndConvertData( pCppReturn
, pUnoReturn
,
255 pReturnTypeDescr
, pThis
->getBridge()->getUno2Cpp() );
256 // destroy temp uno return
257 uno_destructData( pUnoReturn
, pReturnTypeDescr
, 0 );
259 // complex return ptr is set to eax
260 *(void **)pRegisterReturn
= pCppReturn
;
262 if (pReturnTypeDescr
)
264 typelib_TypeClass eRet
=
265 (typelib_TypeClass
)pReturnTypeDescr
->eTypeClass
;
266 TYPELIB_DANGER_RELEASE( pReturnTypeDescr
);
270 return typelib_TypeClass_VOID
;
275 //=====================================================================
276 static typelib_TypeClass
cpp_mediate(
277 sal_Int32 nFunctionIndex
, sal_Int32 nVtableOffset
,
279 sal_Int64
* pRegisterReturn
/* space for register return */ )
281 void ** pCallStack
= (void**)(sp
);
283 fprintf(stderr
, "cpp_mediate with\n");
284 fprintf(stderr
, "%x %x\n", nFunctionIndex
, nVtableOffset
);
285 fprintf(stderr
, "and %x %x\n", pCallStack
, pRegisterReturn
);
286 fprintf(stderr
, "and %x %x\n", pCallStack
[0], pCallStack
[1]);
288 OSL_ENSURE( sizeof(sal_Int32
)==sizeof(void *), "### unexpected!" );
290 void *pThis
= pCallStack
[0];
292 pThis
= static_cast< char * >(pThis
) - nVtableOffset
;
294 bridges::cpp_uno::shared::CppInterfaceProxy
* pCppI
=
295 bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
298 typelib_InterfaceTypeDescription
* pTypeDescr
= pCppI
->getTypeDescr();
300 OSL_ENSURE( nFunctionIndex
< pTypeDescr
->nMapFunctionIndexToMemberIndex
,
301 "### illegal vtable index!" );
302 if (nFunctionIndex
>= pTypeDescr
->nMapFunctionIndexToMemberIndex
)
304 throw RuntimeException(
305 OUString::createFromAscii("illegal vtable index!"),
306 (XInterface
*)pCppI
);
309 // determine called method
310 OSL_ENSURE( nFunctionIndex
< pTypeDescr
->nMapFunctionIndexToMemberIndex
,
311 "### illegal vtable index!" );
312 sal_Int32 nMemberPos
=
313 pTypeDescr
->pMapFunctionIndexToMemberIndex
[nFunctionIndex
];
314 OSL_ENSURE( nMemberPos
< pTypeDescr
->nAllMembers
,
315 "### illegal member index!" );
317 TypeDescription
aMemberDescr( pTypeDescr
->ppAllMembers
[nMemberPos
] );
319 typelib_TypeClass eRet
;
320 switch (aMemberDescr
.get()->eTypeClass
)
322 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
324 if (pTypeDescr
->pMapMemberIndexToFunctionIndex
[nMemberPos
] ==
329 pCppI
, aMemberDescr
.get(),
330 ((typelib_InterfaceAttributeTypeDescription
*)aMemberDescr
.get())->pAttributeTypeRef
,
332 r8
, pCallStack
, pRegisterReturn
);
337 typelib_MethodParameter aParam
;
339 ((typelib_InterfaceAttributeTypeDescription
*)aMemberDescr
.get())->pAttributeTypeRef
;
340 aParam
.bIn
= sal_True
;
341 aParam
.bOut
= sal_False
;
344 pCppI
, aMemberDescr
.get(),
345 0, // indicates void return
347 r8
, pCallStack
, pRegisterReturn
);
351 case typelib_TypeClass_INTERFACE_METHOD
:
354 switch (nFunctionIndex
)
357 pCppI
->acquireProxy(); // non virtual call!
358 eRet
= typelib_TypeClass_VOID
;
361 pCppI
->releaseProxy(); // non virtual call!
362 eRet
= typelib_TypeClass_VOID
;
364 case 0: // queryInterface() opt
366 typelib_TypeDescription
* pTD
= 0;
367 TYPELIB_DANGER_GET(&pTD
,
368 reinterpret_cast<Type
*>(pCallStack
[1])->getTypeLibType());
371 XInterface
* pInterface
= 0;
372 (*pCppI
->getBridge()->getCppEnv()->getRegisteredInterface
)(
373 pCppI
->getBridge()->getCppEnv(),
374 (void **)&pInterface
, pCppI
->getOid().pData
,
375 (typelib_InterfaceTypeDescription
*)pTD
);
380 reinterpret_cast< uno_Any
* >( r8
),
381 &pInterface
, pTD
, cpp_acquire
);
382 pInterface
->release();
383 TYPELIB_DANGER_RELEASE( pTD
);
384 *(void **)pRegisterReturn
= (void*)r8
;
385 eRet
= typelib_TypeClass_ANY
;
388 TYPELIB_DANGER_RELEASE( pTD
);
390 } // else perform queryInterface()
393 pCppI
, aMemberDescr
.get(),
394 ((typelib_InterfaceMethodTypeDescription
*)aMemberDescr
.get())->pReturnTypeRef
,
395 ((typelib_InterfaceMethodTypeDescription
*)aMemberDescr
.get())->nParams
,
396 ((typelib_InterfaceMethodTypeDescription
*)aMemberDescr
.get())->pParams
,
397 r8
, pCallStack
, pRegisterReturn
);
403 throw RuntimeException(
404 OUString::createFromAscii("no member description found!"),
405 (XInterface
*)pCppI
);
407 eRet
= typelib_TypeClass_VOID
;
415 //=======================================================================
417 * is called on incoming vtable calls
418 * (called by asm snippets)
421 extern "C" sal_Int64
cpp_vtable_call( long firstonstack
)
423 register long d0
asm("d0");
424 long functionIndex
= d0
;
426 register long a1
asm("a1");
429 register long d1
asm("d1");
430 long vtableOffset
= d1
;
432 long sp
= (long)&firstonstack
;
434 sal_Int64 nRegReturn
;
435 cpp_mediate( functionIndex
, vtableOffset
, sp
, r8
, &nRegReturn
);
441 const int codeSnippetSize
= 20;
443 //some m68k info : http://www2.biglobe.ne.jp/~inaba/trampolines.html
445 unsigned char *codeSnippet(unsigned char* code
, sal_Int32 functionIndex
,
446 sal_Int32 vtableOffset
)
448 unsigned char * p
= code
;
449 *(short *)&p
[0] = 0x203C; //movel functionIndex,d0
450 *(long *)&p
[2] = functionIndex
;
451 *(short *)&p
[6] = 0x223C; //movel functionIndex,d1
452 *(long *)&p
[8] = vtableOffset
;
453 *(short *)&p
[12] = 0x4EF9; //jmp cpp_vtable_call
454 *(long *)&p
[14] = (long)&cpp_vtable_call
;
455 *(short *)&p
[18] = 0x4E71; //nop
456 return code
+ codeSnippetSize
;
460 struct bridges::cpp_uno::shared::VtableFactory::Slot
{ void * fn
; };
462 bridges::cpp_uno::shared::VtableFactory::Slot
*
463 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block
)
465 return static_cast< Slot
* >(block
) + 2;
468 sal_Size
bridges::cpp_uno::shared::VtableFactory::getBlockSize(
471 return (slotCount
+ 2) * sizeof (Slot
) + slotCount
* codeSnippetSize
;
474 bridges::cpp_uno::shared::VtableFactory::Slot
*
475 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
476 void * block
, sal_Int32 slotCount
)
478 Slot
* slots
= mapBlockToVtable(block
);
481 return slots
+ slotCount
;
484 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
485 Slot
** slots
, unsigned char * code
, sal_PtrDiff writetoexecdiff
,
486 typelib_InterfaceTypeDescription
const * type
, sal_Int32 functionOffset
,
487 sal_Int32 functionCount
, sal_Int32 vtableOffset
)
489 (*slots
) -= functionCount
;
491 for (sal_Int32 i
= 0; i
< type
->nMembers
; ++i
)
493 typelib_TypeDescription
* member
= 0;
494 TYPELIB_DANGER_GET(&member
, type
->ppMembers
[i
]);
495 OSL_ASSERT(member
!= 0);
496 switch (member
->eTypeClass
)
498 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
500 (s
++)->fn
= code
+ writetoexecdiff
;
501 code
= codeSnippet(code
, functionOffset
++, vtableOffset
);
503 if (!reinterpret_cast<
504 typelib_InterfaceAttributeTypeDescription
* >(
507 (s
++)->fn
= code
+ writetoexecdiff
;
508 code
= codeSnippet(code
, functionOffset
++, vtableOffset
);
511 case typelib_TypeClass_INTERFACE_METHOD
:
513 (s
++)->fn
= code
+ writetoexecdiff
;
515 typelib_InterfaceMethodTypeDescription
*pMethodTD
=
517 typelib_InterfaceMethodTypeDescription
* >(member
);
519 bool issimple
= bridges::cpp_uno::shared::isSimpleType(
520 pMethodTD
->pReturnTypeRef
);
522 code
= codeSnippet(code
, functionOffset
++, vtableOffset
);
529 TYPELIB_DANGER_RELEASE(member
);
534 void bridges::cpp_uno::shared::VtableFactory::flushCode(
535 unsigned char const * /*beg*/, unsigned char const * /*end*/)
539 /* vi:set tabstop=4 shiftwidth=4 expandtab: */