1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 #include <malloc.h>
25 #include <rtl/alloc.h>
26
27 #include <com/sun/star/uno/genfunc.hxx>
28 #include "com/sun/star/uno/RuntimeException.hpp"
29 #include <uno/data.h>
30
31 #include <bridges/cpp_uno/shared/bridge.hxx>
32 #include <bridges/cpp_uno/shared/types.hxx>
33 #include <bridges/cpp_uno/shared/unointerfaceproxy.hxx>
34 #include <bridges/cpp_uno/shared/vtables.hxx>
35
36 #include "share.hxx"
37
38 #include <stdio.h>
39 #include <string.h>
40
41 using namespace ::rtl;
42 using namespace ::com::sun::star::uno;
43
44 void callVirtualMethod(void * pThis, sal_uInt32 nVtableIndex,
45 void * pRegisterReturn, typelib_TypeDescription *pReturnTypeDescr, bool bRegisterReturn,
46 sal_uInt32 *pStack, sal_uInt32 nStack, sal_uInt32 *pGPR, double *pFPR);
47
48 #define INSERT_INT32( pSV, nr, pGPR, pDS, bOverFlow )\
49 if (nr < hppa::MAX_WORDS_IN_REGS) \
50 { \
51 pGPR[nr++] = *reinterpret_cast<sal_uInt32 *>( pSV ); \
52 } \
53 else \
54 bOverFlow = true; \
55 if (bOverFlow) \
56 *pDS++ = *reinterpret_cast<sal_uInt32 *>( pSV );
57
58 #define INSERT_INT64( pSV, nr, pGPR, pDS, pStart, bOverFlow )\
59 if ( (nr < hppa::MAX_WORDS_IN_REGS) && (nr % 2) ) \
60 { \
61 ++nr; \
62 } \
63 if ( nr < hppa::MAX_WORDS_IN_REGS ) \
64 { \
65 pGPR[nr++] = *reinterpret_cast<sal_uInt32 *>( pSV ); \
66 pGPR[nr++] = *(reinterpret_cast<sal_uInt32 *>( pSV ) + 1); \
67 } \
68 else \
69 bOverFlow = true; \
70 if ( bOverFlow ) \
71 { \
72 if ( (pDS - pStart) % 2) \
73 ++pDS; \
74 *pDS++ = reinterpret_cast<sal_uInt32 *>( pSV )[1]; \
75 *pDS++ = reinterpret_cast<sal_uInt32 *>( pSV )[0]; \
76 }
77
78 #define INSERT_FLOAT( pSV, nr, pFPR, pDS, bOverFlow ) \
79 if (nr < hppa::MAX_WORDS_IN_REGS) \
80 { \
81 sal_uInt32 *pDouble = (sal_uInt32 *)&(pFPR[nr++]); \
82 pDouble[0] = *reinterpret_cast<sal_uInt32 *>( pSV ); \
83 } \
84 else \
85 bOverFlow = true; \
86 if (bOverFlow) \
87 *pDS++ = *reinterpret_cast<sal_uInt32 *>( pSV );
88
89 #define INSERT_DOUBLE( pSV, nr, pFPR, pDS, pStart, bOverFlow ) \
90 if ( (nr < hppa::MAX_WORDS_IN_REGS) && (nr % 2) ) \
91 { \
92 ++nr; \
93 } \
94 if ( nr < hppa::MAX_WORDS_IN_REGS ) \
95 { \
96 sal_uInt32 *pDouble = (sal_uInt32 *)&(pFPR[nr+1]); \
97 pDouble[0] = *reinterpret_cast<sal_uInt32 *>( pSV ); \
98 pDouble[1] = *(reinterpret_cast<sal_uInt32 *>( pSV ) + 1); \
99 nr+=2; \
100 } \
101 else \
102 bOverFlow = true; \
103 if ( bOverFlow ) \
104 { \
105 if ( (pDS - pStart) % 2) \
106 ++pDS; \
107 *pDS++ = reinterpret_cast<sal_uInt32 *>( pSV )[1]; \
108 *pDS++ = reinterpret_cast<sal_uInt32 *>( pSV )[0]; \
109 }
110
111 #define INSERT_INT16( pSV, nr, pGPR, pDS, bOverFlow ) \
112 if ( nr < hppa::MAX_WORDS_IN_REGS ) \
113 pGPR[nr++] = *reinterpret_cast<sal_uInt16 *>( pSV ); \
114 else \
115 bOverFlow = true; \
116 if (bOverFlow) \
117 *pDS++ = *reinterpret_cast<sal_uInt16 *>( pSV );
118
119 #define INSERT_INT8( pSV, nr, pGPR, pDS, bOverFlow ) \
120 if ( nr < hppa::MAX_WORDS_IN_REGS ) \
121 pGPR[nr++] = *reinterpret_cast<sal_uInt8 *>( pSV ); \
122 else \
123 bOverFlow = true; \
124 if (bOverFlow) \
125 *pDS++ = *reinterpret_cast<sal_uInt8 *>( pSV );
126
127 namespace hppa
128 {
is_complex_struct(const typelib_TypeDescription * type)129 bool is_complex_struct(const typelib_TypeDescription * type)
130 {
131 const typelib_CompoundTypeDescription * p
132 = reinterpret_cast< const typelib_CompoundTypeDescription * >(type);
133 for (sal_Int32 i = 0; i < p->nMembers; ++i)
134 {
135 if (p->ppTypeRefs[i]->eTypeClass == typelib_TypeClass_STRUCT ||
136 p->ppTypeRefs[i]->eTypeClass == typelib_TypeClass_EXCEPTION)
137 {
138 typelib_TypeDescription * t = 0;
139 TYPELIB_DANGER_GET(&t, p->ppTypeRefs[i]);
140 bool b = is_complex_struct(t);
141 TYPELIB_DANGER_RELEASE(t);
142 if (b) {
143 return true;
144 }
145 }
146 else if (!bridges::cpp_uno::shared::isSimpleType(p->ppTypeRefs[i]->eTypeClass))
147 return true;
148 }
149 if (p->pBaseTypeDescription != 0)
150 return is_complex_struct(&p->pBaseTypeDescription->aBase);
151 return false;
152 }
153
isRegisterReturn(typelib_TypeDescriptionReference * pTypeRef)154 bool isRegisterReturn( typelib_TypeDescriptionReference *pTypeRef )
155 {
156 if (bridges::cpp_uno::shared::isSimpleType(pTypeRef))
157 return true;
158 else if (pTypeRef->eTypeClass == typelib_TypeClass_STRUCT || pTypeRef->eTypeClass == typelib_TypeClass_EXCEPTION)
159 {
160 typelib_TypeDescription * pTypeDescr = 0;
161 TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
162
163 /* If the struct is larger than 8 bytes, then there is a buffer at r8 to stick the return value into */
164 bool bRet = pTypeDescr->nSize <= 8 && !is_complex_struct(pTypeDescr);
165
166 TYPELIB_DANGER_RELEASE( pTypeDescr );
167 return bRet;
168 }
169 return false;
170 }
171 }
172
173
174 namespace {
175 //=======================================================================
cpp_call(bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,bridges::cpp_uno::shared::VtableSlot aVtableSlot,typelib_TypeDescriptionReference * pReturnTypeRef,sal_Int32 nParams,typelib_MethodParameter * pParams,void * pUnoReturn,void * pUnoArgs[],uno_Any ** ppUnoExc)176 static void cpp_call(
177 bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
178 bridges::cpp_uno::shared::VtableSlot aVtableSlot,
179 typelib_TypeDescriptionReference * pReturnTypeRef,
180 sal_Int32 nParams, typelib_MethodParameter * pParams,
181 void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
182 {
183 // max space for: [complex ret ptr], values|ptr ...
184 sal_uInt32 * pStack = (sal_uInt32 *)__builtin_alloca(
185 sizeof(sal_Int32) + ((nParams+2) * sizeof(sal_Int64)) );
186 sal_uInt32 * pStackStart = pStack;
187
188 sal_uInt32 pGPR[hppa::MAX_GPR_REGS];
189 double pFPR[hppa::MAX_SSE_REGS];
190 sal_uInt32 nRegs=0;
191
192 // return
193 typelib_TypeDescription * pReturnTypeDescr = 0;
194 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
195 OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" );
196
197 void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
198 bool bOverFlow = false;
199 bool bRegisterReturn = true;
200
201 if (pReturnTypeDescr)
202 {
203
204 bRegisterReturn = hppa::isRegisterReturn(pReturnTypeRef);
205 if (bRegisterReturn)
206 pCppReturn = pUnoReturn; // direct way for simple types
207 else
208 {
209 // complex return via ptr
210 pCppReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
211 ? __builtin_alloca( pReturnTypeDescr->nSize )
212 : pUnoReturn); // direct way
213 }
214 }
215 // push this
216 void * pAdjustedThisPtr = reinterpret_cast< void ** >(pThis->getCppI())
217 + aVtableSlot.offset;
218 INSERT_INT32( &pAdjustedThisPtr, nRegs, pGPR, pStack, bOverFlow );
219
220 // stack space
221 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" );
222 // args
223 void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams );
224 // indizes of values this have to be converted (interface conversion cpp<=>uno)
225 sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams);
226 // type descriptions for reconversions
227 typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
228
229 sal_Int32 nTempIndizes = 0;
230
231 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
232 {
233 const typelib_MethodParameter & rParam = pParams[nPos];
234 typelib_TypeDescription * pParamTypeDescr = 0;
235 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
236
237 if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
238 {
239 uno_copyAndConvertData( pCppArgs[nPos] = alloca(8), pUnoArgs[nPos],
240 pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
241
242 switch (pParamTypeDescr->eTypeClass)
243 {
244 case typelib_TypeClass_HYPER:
245 case typelib_TypeClass_UNSIGNED_HYPER:
246 #ifdef CMC_DEBUG
247 fprintf(stderr, "hyper is %llx\n", *((long long*)pCppArgs[nPos]));
248 #endif
249 INSERT_INT64( pCppArgs[nPos], nRegs, pGPR, pStack, pStackStart, bOverFlow );
250 break;
251 case typelib_TypeClass_LONG:
252 case typelib_TypeClass_UNSIGNED_LONG:
253 case typelib_TypeClass_ENUM:
254 #ifdef CMC_DEBUG
255 fprintf(stderr, "long is %x\n", pCppArgs[nPos]);
256 #endif
257 INSERT_INT32( pCppArgs[nPos], nRegs, pGPR, pStack, bOverFlow );
258 break;
259 case typelib_TypeClass_SHORT:
260 case typelib_TypeClass_CHAR:
261 case typelib_TypeClass_UNSIGNED_SHORT:
262 INSERT_INT16( pCppArgs[nPos], nRegs, pGPR, pStack, bOverFlow );
263 break;
264 case typelib_TypeClass_BOOLEAN:
265 case typelib_TypeClass_BYTE:
266 INSERT_INT8( pCppArgs[nPos], nRegs, pGPR, pStack, bOverFlow );
267 break;
268 case typelib_TypeClass_FLOAT:
269 INSERT_FLOAT( pCppArgs[nPos], nRegs, pFPR, pStack, bOverFlow );
270 break;
271 case typelib_TypeClass_DOUBLE:
272 INSERT_DOUBLE( pCppArgs[nPos], nRegs, pFPR, pStack, pStackStart, bOverFlow );
273 break;
274 default:
275 break;
276 }
277 // no longer needed
278 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
279 }
280 else // ptr to complex value | ref
281 {
282 if (! rParam.bIn) // is pure out
283 {
284 // cpp out is constructed mem, uno out is not!
285 uno_constructData(
286 pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
287 pParamTypeDescr );
288 pTempIndizes[nTempIndizes] = nPos; // default constructed for cpp call
289 // will be released at reconversion
290 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
291 }
292 // is in/inout
293 else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
294 {
295 uno_copyAndConvertData(
296 pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
297 pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
298
299 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
300 // will be released at reconversion
301 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
302 }
303 else // direct way
304 {
305 pCppArgs[nPos] = pUnoArgs[nPos];
306 // no longer needed
307 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
308 }
309 INSERT_INT32( &(pCppArgs[nPos]), nRegs, pGPR, pStack, bOverFlow );
310 }
311 }
312
313 try
314 {
315 callVirtualMethod(
316 pAdjustedThisPtr, aVtableSlot.index,
317 pCppReturn, pReturnTypeDescr, bRegisterReturn,
318 pStackStart,
319 (pStack - pStackStart), pGPR, pFPR);
320
321 // NO exception occurred...
322 *ppUnoExc = 0;
323
324 // reconvert temporary params
325 for ( ; nTempIndizes--; )
326 {
327 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
328 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
329
330 if (pParams[nIndex].bIn)
331 {
332 if (pParams[nIndex].bOut) // inout
333 {
334 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
335 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
336 pThis->getBridge()->getCpp2Uno() );
337 }
338 }
339 else // pure out
340 {
341 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
342 pThis->getBridge()->getCpp2Uno() );
343 }
344 // destroy temp cpp param => cpp: every param was constructed
345 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
346
347 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
348 }
349 // return value
350 if (pCppReturn && pUnoReturn != pCppReturn)
351 {
352 uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
353 pThis->getBridge()->getCpp2Uno() );
354 uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
355 }
356 }
357 catch (...)
358 {
359 // fill uno exception
360 fillUnoException( CPPU_CURRENT_NAMESPACE::__cxa_get_globals()->caughtExceptions, *ppUnoExc, pThis->getBridge()->getCpp2Uno() );
361
362 // temporary params
363 for ( ; nTempIndizes--; )
364 {
365 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
366 // destroy temp cpp param => cpp: every param was constructed
367 uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], cpp_release );
368 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
369 }
370
371 // return type
372 if (pReturnTypeDescr)
373 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
374 }
375 }
376 }
377
378 namespace bridges { namespace cpp_uno { namespace shared {
379
unoInterfaceProxyDispatch(uno_Interface * pUnoI,const typelib_TypeDescription * pMemberDescr,void * pReturn,void * pArgs[],uno_Any ** ppException)380 void unoInterfaceProxyDispatch(
381 uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
382 void * pReturn, void * pArgs[], uno_Any ** ppException )
383 {
384 // is my surrogate
385 bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
386 = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
387 #if OSL_DEBUG_LEVEL > 0
388 typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
389 #endif
390
391 switch (pMemberDescr->eTypeClass)
392 {
393 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
394 {
395 #if OSL_DEBUG_LEVEL > 0
396 // determine vtable call index
397 sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition;
398 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### member pos out of range!" );
399 #endif
400
401 VtableSlot aVtableSlot(
402 getVtableSlot(
403 reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>
404 (pMemberDescr)));
405
406 if (pReturn)
407 {
408 // dependent dispatch
409 cpp_call(
410 pThis, aVtableSlot,
411 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
412 0, 0, // no params
413 pReturn, pArgs, ppException );
414 }
415 else
416 {
417 // is SET
418 typelib_MethodParameter aParam;
419 aParam.pTypeRef =
420 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
421 aParam.bIn = sal_True;
422 aParam.bOut = sal_False;
423
424 typelib_TypeDescriptionReference * pReturnTypeRef = 0;
425 OUString aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") );
426 typelib_typedescriptionreference_new(
427 &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
428
429 // dependent dispatch
430 aVtableSlot.index += 1;
431 cpp_call(
432 pThis, aVtableSlot, // get, then set method
433 pReturnTypeRef,
434 1, &aParam,
435 pReturn, pArgs, ppException );
436
437 typelib_typedescriptionreference_release( pReturnTypeRef );
438 }
439
440 break;
441 }
442 case typelib_TypeClass_INTERFACE_METHOD:
443 {
444 #if OSL_DEBUG_LEVEL > 0
445 // determine vtable call index
446 sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition;
447 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### member pos out of range!" );
448 #endif
449
450 VtableSlot aVtableSlot(
451 getVtableSlot(
452 reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>
453 (pMemberDescr)));
454
455 switch (aVtableSlot.index)
456 {
457 // standard calls
458 case 1: // acquire uno interface
459 (*pUnoI->acquire)( pUnoI );
460 *ppException = 0;
461 break;
462 case 2: // release uno interface
463 (*pUnoI->release)( pUnoI );
464 *ppException = 0;
465 break;
466 case 0: // queryInterface() opt
467 {
468 typelib_TypeDescription * pTD = 0;
469 TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() );
470 if (pTD)
471 {
472 uno_Interface * pInterface = 0;
473 (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)(
474 pThis->getBridge()->getUnoEnv(),
475 (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
476
477 if (pInterface)
478 {
479 ::uno_any_construct(
480 reinterpret_cast< uno_Any * >( pReturn ),
481 &pInterface, pTD, 0 );
482 (*pInterface->release)( pInterface );
483 TYPELIB_DANGER_RELEASE( pTD );
484 *ppException = 0;
485 break;
486 }
487
488 TYPELIB_DANGER_RELEASE( pTD );
489 }
490 } // else perform queryInterface()
491 default:
492 // dependent dispatch
493 cpp_call(
494 pThis, aVtableSlot,
495 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef,
496 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams,
497 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams,
498 pReturn, pArgs, ppException );
499 }
500 break;
501 }
502 default:
503 {
504 ::com::sun::star::uno::RuntimeException aExc(
505 OUString( RTL_CONSTASCII_USTRINGPARAM("illegal member type description!") ),
506 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
507
508 Type const & rExcType = ::getCppuType( &aExc );
509 // binary identical null reference
510 ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
511 }
512 }
513 }
514
515 } } }
516
517 /* vi:set tabstop=4 shiftwidth=4 expandtab: */
518