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
MapReturn(long d0,long d1,typelib_TypeClass eReturnType,long * pRegisterReturn)44 void MapReturn(long d0, long d1, typelib_TypeClass eReturnType, long *pRegisterReturn)
45 {
46 register float fret asm("fp0");
47 register double dret asm("fp0");
48
49 switch( eReturnType )
50 {
51 case typelib_TypeClass_HYPER:
52 case typelib_TypeClass_UNSIGNED_HYPER:
53 pRegisterReturn[1] = d1;
54 case typelib_TypeClass_LONG:
55 case typelib_TypeClass_UNSIGNED_LONG:
56 case typelib_TypeClass_ENUM:
57 case typelib_TypeClass_CHAR:
58 case typelib_TypeClass_SHORT:
59 case typelib_TypeClass_UNSIGNED_SHORT:
60 case typelib_TypeClass_BOOLEAN:
61 case typelib_TypeClass_BYTE:
62 pRegisterReturn[0] = d0;
63 break;
64 case typelib_TypeClass_FLOAT:
65 *(float*)pRegisterReturn = fret;
66 break;
67 case typelib_TypeClass_DOUBLE:
68 *(double*)pRegisterReturn = dret;
69 break;
70 default:
71 break;
72 }
73 }
74
75 namespace
76 {
77 //================================================================
78
79 void callVirtualMethod(
80 void * pThis,
81 sal_Int32 nVtableIndex,
82 void * pRegisterReturn,
83 typelib_TypeClass eReturnType,
84 sal_uInt32 *pStack,
85 sal_uInt32 nStack) __attribute__((noinline));
86
callVirtualMethod(void * pThis,sal_Int32 nVtableIndex,void * pRegisterReturn,typelib_TypeClass eReturnType,sal_uInt32 * pStack,sal_uInt32 nStack)87 void callVirtualMethod(
88 void * pThis,
89 sal_Int32 nVtableIndex,
90 void * pRegisterReturn,
91 typelib_TypeClass eReturnType,
92 sal_uInt32 *pStack,
93 sal_uInt32 nStack)
94 {
95 // never called
96 if (! pThis)
97 CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything("xxx"); // address something
98
99 if ( nStack )
100 {
101 // m68k stack is either 2 or 4 bytes aligned, doesn't really matter as
102 // we deal in 4 byte units anyway
103 sal_uInt32 nStackBytes = nStack * sizeof(sal_uInt32);
104 sal_uInt32 *stack = (sal_uInt32 *) __builtin_alloca( nStackBytes );
105 memcpy( stack, pStack, nStackBytes );
106 }
107
108 #ifdef CMC_DEBUG
109 // Let's figure out what is really going on here
110 {
111 fprintf( stderr, "\nStack (%d): ", nStack );
112 for ( unsigned int i = 0; i < nStack; ++i )
113 fprintf( stderr, "0x%lx, ", pStack[i] );
114 fprintf( stderr, "\n" );
115 fprintf( stderr, "pRegisterReturn is %p\n", pRegisterReturn);
116 }
117 #endif
118
119 sal_uInt32 pMethod = *((sal_uInt32*)pThis);
120 pMethod += 4 * nVtableIndex;
121 pMethod = *((sal_uInt32 *)pMethod);
122
123 typedef long (*FunctionCall )();
124 FunctionCall pFunc = (FunctionCall)pMethod;
125
126 //stick the return area into r8 for big struct returning
127 asm volatile("movel %0,%%a1" : : "m"(pRegisterReturn) : );
128
129 long d0 = (*pFunc)();
130
131 register long d1 asm("d1");
132
133 MapReturn(d0, d1, eReturnType, (long*)pRegisterReturn);
134 }
135 }
136
137 #define INSERT_INT32( pSV, pDS )\
138 *pDS++ = *reinterpret_cast<sal_uInt32 *>( pSV );
139
140 #define INSERT_INT64( pSV, pDS )\
141 INSERT_INT32( pSV, pDS ) \
142 INSERT_INT32( ((sal_uInt32*)pSV)+1, pDS )
143
144 #define INSERT_FLOAT( pSV, pDS ) \
145 INSERT_INT32( pSV, pDS )
146
147 #define INSERT_DOUBLE( pSV, pDS ) \
148 INSERT_INT64( pSV, pDS )
149
150 #define INSERT_INT16( pSV, pDS ) \
151 *pDS++ = *reinterpret_cast<sal_uInt16 *>( pSV );
152
153 #define INSERT_INT8( pSV, pDS ) \
154 *pDS++ = *reinterpret_cast<sal_uInt8 *>( pSV );
155
156 namespace {
157 //=======================================================================
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)158 static void cpp_call(
159 bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
160 bridges::cpp_uno::shared::VtableSlot aVtableSlot,
161 typelib_TypeDescriptionReference * pReturnTypeRef,
162 sal_Int32 nParams, typelib_MethodParameter * pParams,
163 void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
164 {
165
166 // max space for: [complex ret ptr], values|ptr ...
167 sal_uInt32 * pStack = (sal_uInt32 *)__builtin_alloca(
168 sizeof(sal_Int32) + ((nParams+2) * sizeof(sal_Int64)) );
169 sal_uInt32 * pStackStart = pStack;
170
171 // return
172 typelib_TypeDescription * pReturnTypeDescr = 0;
173 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
174 OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" );
175
176 void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
177
178 if (pReturnTypeDescr)
179 {
180
181 if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr ))
182 {
183 pCppReturn = pUnoReturn; // direct way for simple types
184 }
185 else
186 {
187 // complex return via ptr
188 pCppReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
189 ? __builtin_alloca( pReturnTypeDescr->nSize )
190 : pUnoReturn); // direct way
191
192 // INSERT_INT32( &pCppReturn, pStack );
193 }
194 }
195 // push this
196 void * pAdjustedThisPtr = reinterpret_cast< void ** >(pThis->getCppI())
197 + aVtableSlot.offset;
198 INSERT_INT32( &pAdjustedThisPtr, pStack );
199
200 // stack space
201 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" );
202 // args
203 void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams );
204 // indizes of values this have to be converted (interface conversion cpp<=>uno)
205 sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams);
206 // type descriptions for reconversions
207 typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
208
209 sal_Int32 nTempIndizes = 0;
210
211 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
212 {
213 const typelib_MethodParameter & rParam = pParams[nPos];
214 typelib_TypeDescription * pParamTypeDescr = 0;
215 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
216
217 if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
218 {
219 // uno_copyAndConvertData( pCppArgs[nPos] = pStack, pUnoArgs[nPos],
220 uno_copyAndConvertData( pCppArgs[nPos] = alloca(8), pUnoArgs[nPos],
221 pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
222
223 switch (pParamTypeDescr->eTypeClass)
224 {
225 case typelib_TypeClass_HYPER:
226 case typelib_TypeClass_UNSIGNED_HYPER:
227 #ifdef CMC_DEBUG
228 fprintf(stderr, "hyper is %lx\n", pCppArgs[nPos]);
229 #endif
230 INSERT_INT64( pCppArgs[nPos], pStack );
231 break;
232 case typelib_TypeClass_LONG:
233 case typelib_TypeClass_UNSIGNED_LONG:
234 case typelib_TypeClass_ENUM:
235 #ifdef CMC_DEBUG
236 fprintf(stderr, "long is %x\n", pCppArgs[nPos]);
237 #endif
238 INSERT_INT32( pCppArgs[nPos], pStack );
239 break;
240 case typelib_TypeClass_SHORT:
241 case typelib_TypeClass_CHAR:
242 case typelib_TypeClass_UNSIGNED_SHORT:
243 INSERT_INT16( pCppArgs[nPos], pStack );
244 break;
245 case typelib_TypeClass_BOOLEAN:
246 case typelib_TypeClass_BYTE:
247 INSERT_INT8( pCppArgs[nPos], pStack );
248 break;
249 case typelib_TypeClass_FLOAT:
250 INSERT_FLOAT( pCppArgs[nPos], pStack );
251 break;
252 case typelib_TypeClass_DOUBLE:
253 INSERT_DOUBLE( pCppArgs[nPos], pStack );
254 break;
255 }
256 // no longer needed
257 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
258 }
259 else // ptr to complex value | ref
260 {
261 if (! rParam.bIn) // is pure out
262 {
263 // cpp out is constructed mem, uno out is not!
264 uno_constructData(
265 pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
266 pParamTypeDescr );
267 pTempIndizes[nTempIndizes] = nPos; // default constructed for cpp call
268 // will be released at reconversion
269 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
270 }
271 // is in/inout
272 else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
273 {
274 uno_copyAndConvertData(
275 pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
276 pUnoArgs[nPos], pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
277
278 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
279 // will be released at reconversion
280 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
281 }
282 else // direct way
283 {
284 pCppArgs[nPos] = pUnoArgs[nPos];
285 // no longer needed
286 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
287 }
288 INSERT_INT32( &(pCppArgs[nPos]), pStack );
289 }
290 }
291
292 try
293 {
294 callVirtualMethod(
295 pAdjustedThisPtr, aVtableSlot.index,
296 pCppReturn, pReturnTypeDescr->eTypeClass,
297 pStackStart,
298 (pStack - pStackStart));
299
300 // NO exception occurred...
301 *ppUnoExc = 0;
302
303 // reconvert temporary params
304 for ( ; nTempIndizes--; )
305 {
306 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
307 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
308
309 if (pParams[nIndex].bIn)
310 {
311 if (pParams[nIndex].bOut) // inout
312 {
313 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
314 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
315 pThis->getBridge()->getCpp2Uno() );
316 }
317 }
318 else // pure out
319 {
320 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
321 pThis->getBridge()->getCpp2Uno() );
322 }
323 // destroy temp cpp param => cpp: every param was constructed
324 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
325
326 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
327 }
328 // return value
329 if (pCppReturn && pUnoReturn != pCppReturn)
330 {
331 uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
332 pThis->getBridge()->getCpp2Uno() );
333 uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
334 }
335 }
336 catch (...)
337 {
338 // fill uno exception
339 fillUnoException( CPPU_CURRENT_NAMESPACE::__cxa_get_globals()->caughtExceptions, *ppUnoExc, pThis->getBridge()->getCpp2Uno() );
340
341 // temporary params
342 for ( ; nTempIndizes--; )
343 {
344 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
345 // destroy temp cpp param => cpp: every param was constructed
346 uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], cpp_release );
347 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
348 }
349
350 // return type
351 if (pReturnTypeDescr)
352 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
353 }
354 }
355 }
356
357 namespace bridges { namespace cpp_uno { namespace shared {
358
unoInterfaceProxyDispatch(uno_Interface * pUnoI,const typelib_TypeDescription * pMemberDescr,void * pReturn,void * pArgs[],uno_Any ** ppException)359 void unoInterfaceProxyDispatch(
360 uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
361 void * pReturn, void * pArgs[], uno_Any ** ppException )
362 {
363 // is my surrogate
364 bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
365 = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
366 typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
367
368 switch (pMemberDescr->eTypeClass)
369 {
370 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
371 {
372 // determine vtable call index
373 sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition;
374 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### member pos out of range!" );
375
376 VtableSlot aVtableSlot(
377 getVtableSlot(
378 reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>
379 (pMemberDescr)));
380
381 if (pReturn)
382 {
383 // dependent dispatch
384 cpp_call(
385 pThis, aVtableSlot,
386 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
387 0, 0, // no params
388 pReturn, pArgs, ppException );
389 }
390 else
391 {
392 // is SET
393 typelib_MethodParameter aParam;
394 aParam.pTypeRef =
395 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
396 aParam.bIn = sal_True;
397 aParam.bOut = sal_False;
398
399 typelib_TypeDescriptionReference * pReturnTypeRef = 0;
400 OUString aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") );
401 typelib_typedescriptionreference_new(
402 &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
403
404 // dependent dispatch
405 aVtableSlot.index += 1;
406 cpp_call(
407 pThis, aVtableSlot, // get, then set method
408 pReturnTypeRef,
409 1, &aParam,
410 pReturn, pArgs, ppException );
411
412 typelib_typedescriptionreference_release( pReturnTypeRef );
413 }
414
415 break;
416 }
417 case typelib_TypeClass_INTERFACE_METHOD:
418 {
419 // determine vtable call index
420 sal_Int32 nMemberPos = ((typelib_InterfaceMemberTypeDescription *)pMemberDescr)->nPosition;
421 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### member pos out of range!" );
422
423 VtableSlot aVtableSlot(
424 getVtableSlot(
425 reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>
426 (pMemberDescr)));
427
428 switch (aVtableSlot.index)
429 {
430 // standard calls
431 case 1: // acquire uno interface
432 (*pUnoI->acquire)( pUnoI );
433 *ppException = 0;
434 break;
435 case 2: // release uno interface
436 (*pUnoI->release)( pUnoI );
437 *ppException = 0;
438 break;
439 case 0: // queryInterface() opt
440 {
441 typelib_TypeDescription * pTD = 0;
442 TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() );
443 if (pTD)
444 {
445 uno_Interface * pInterface = 0;
446 (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)(
447 pThis->getBridge()->getUnoEnv(),
448 (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
449
450 if (pInterface)
451 {
452 ::uno_any_construct(
453 reinterpret_cast< uno_Any * >( pReturn ),
454 &pInterface, pTD, 0 );
455 (*pInterface->release)( pInterface );
456 TYPELIB_DANGER_RELEASE( pTD );
457 *ppException = 0;
458 break;
459 }
460 TYPELIB_DANGER_RELEASE( pTD );
461 }
462 } // else perform queryInterface()
463 default:
464 // dependent dispatch
465 cpp_call(
466 pThis, aVtableSlot,
467 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef,
468 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams,
469 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams,
470 pReturn, pArgs, ppException );
471 }
472 break;
473 }
474 default:
475 {
476 ::com::sun::star::uno::RuntimeException aExc(
477 OUString( RTL_CONSTASCII_USTRINGPARAM("illegal member type description!") ),
478 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
479
480 Type const & rExcType = ::getCppuType( &aExc );
481 // binary identical null reference
482 ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
483 }
484 }
485 }
486
487 } } }
488
489 /* vi:set tabstop=4 shiftwidth=4 expandtab: */
490