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
26 #include <com/sun/star/uno/genfunc.hxx>
27 #include <uno/data.h>
28
29 #include "bridges/cpp_uno/shared/bridge.hxx"
30 #include "bridges/cpp_uno/shared/types.hxx"
31 #include "bridges/cpp_uno/shared/unointerfaceproxy.hxx"
32 #include "bridges/cpp_uno/shared/vtables.hxx"
33
34 #include "share.hxx"
35
36 //#define BRDEBUG
37 #ifdef BRDEBUG
38 #include <stdio.h>
39 #endif
40
41
42 using namespace ::rtl;
43 using namespace ::com::sun::star::uno;
44
45 namespace
46 {
47
48
49 //==================================================================================================
callVirtualMethod(void * pAdjustedThisPtr,sal_Int32 nVtableIndex,void * pRegisterReturn,typelib_TypeClass eReturnType,char * pPT,sal_Int32 * pStackLongs,sal_Int32)50 static void callVirtualMethod(
51 void * pAdjustedThisPtr,
52 sal_Int32 nVtableIndex,
53 void * pRegisterReturn,
54 typelib_TypeClass eReturnType,
55 char * pPT,
56 sal_Int32 * pStackLongs,
57 sal_Int32 /*nStackLongs*/)
58 {
59
60 // parameter list is mixed list of * and values
61 // reference parameters are pointers
62
63 unsigned long * mfunc; // actual function to be invoked
64 void (*ptr)();
65 int gpr[4]; // storage for gpregisters, map to a0-a3
66 int off; // offset used to find function
67 int nw; // number of words mapped
68 long *p; // pointer to parameter overflow area
69 int c; // character of parameter type being decoded
70 int iret, iret2; // temporary function return values
71
72 // never called
73 if (! pAdjustedThisPtr ) CPPU_CURRENT_NAMESPACE::dummy_can_throw_anything("xxx"); // address something
74
75 #ifdef BRDEBUG
76 fprintf(stderr,"in CallVirtualMethod\n");
77 #endif
78
79 // Because of the MIPS O32 calling conventions we could be passing
80 // parameters in both register types and on the stack. To create the
81 // stack parameter area we need we now simply allocate local
82 // variable storage param[] that is at least the size of the parameter stack
83 // (more than enough space) which we can overwrite the parameters into.
84
85 /* p = sp - 512; new sp will be p - 16, but we don't change sp
86 * at this time to avoid breaking ABI--not sure whether changing sp will break
87 * references to local variables. For the same reason, we use abosulte value.
88 */
89 __asm__ __volatile__ (
90 "addiu $2,$29,-512\n\t"
91 "move %0,$2\n\t"
92 :"=r"(p): : "$2","$29" );
93
94 #ifdef BRDEBUG
95 if (nStackLongs * 4 > 512 )
96 fprintf(stderr,"too many arguments");
97 #endif
98
99 // now begin to load the C++ function arguments into storage
100 nw = 0;
101
102 // now we need to parse the entire signature string */
103 // until we get the END indicator */
104
105 // treat complex return pointer like any other parameter //
106
107 #ifdef BRDEBUG
108 fprintf(stderr,"overflow area pointer p=%p\n",p);
109
110 /* Let's figure out what is really going on here*/
111 fprintf(stderr,"callVirtualMethod paramters string is %s\n",pPT);
112 int k = nStackLongs;
113 long * q = (long *)pStackLongs;
114 while (k > 0) {
115 fprintf(stderr,"uno stack is: %x\n",(unsigned int)*q);
116 k--;
117 q++;
118 }
119 #endif
120
121 /* parse the argument list up to the ending ) */
122 while (*pPT != 'X') {
123 c = *pPT;
124 switch (c) {
125 case 'D': /* type is double */
126 /* treat the same as long long */
127 case 'H': /* type is long long */
128 if (nw & 1) nw++; /* note even elements gpr[] will map to
129 odd registers*/
130 if (nw < 4) {
131 gpr[nw++] = *pStackLongs;
132 gpr[nw++] = *(pStackLongs+1);
133 } else {
134 if (((long) p) & 4)
135 p++;
136 *p++ = *pStackLongs;
137 *p++ = *(pStackLongs+1);
138 }
139 pStackLongs += 2;
140 break;
141
142 case 'S':
143 if (nw < 4) {
144 gpr[nw++] = *((unsigned short*)pStackLongs);
145 } else {
146 *p++ = *((unsigned short *)pStackLongs);
147 }
148 pStackLongs += 1;
149 break;
150
151 case 'B':
152 if (nw < 4) {
153 gpr[nw++] = *((char *)pStackLongs);
154 } else {
155 *p++ = *((char *)pStackLongs);
156 }
157 pStackLongs += 1;
158 break;
159
160 default:
161 if (nw < 4) {
162 gpr[nw++] = *pStackLongs;
163 } else {
164 *p++ = *pStackLongs;
165 }
166 pStackLongs += 1;
167 break;
168 }
169 pPT++;
170 }
171
172 /* figure out the address of the function we need to invoke */
173 off = nVtableIndex;
174 off = off * 4; // 4 bytes per slot
175 mfunc = *((unsigned long **)pAdjustedThisPtr); // get the address of the vtable
176 mfunc = (unsigned long *)((char *)mfunc + off); // get the address from the vtable entry at offset
177 mfunc = *((unsigned long **)mfunc); // the function is stored at the address
178 ptr = (void (*)())mfunc;
179
180 #ifdef BRDEBUG
181 fprintf(stderr,"calling function %p\n",mfunc);
182 #endif
183
184 /* Set up the machine registers and invoke the function */
185
186 __asm__ __volatile__ (
187 "lw $4, 0(%0)\n\t"
188 "lw $5, 4(%0)\n\t"
189 "lw $6, 8(%0)\n\t"
190 "lw $7, 12(%0)\n\t"
191 : : "r" (gpr)
192 : "$4", "$5", "$6", "$7"
193 );
194
195 __asm__ __volatile__ ("addiu $29,$29,-528\r\n":::"$29");
196
197 (*ptr)();
198
199 __asm__ __volatile__ ("addiu $29,$29,528\r\n":::"$29");
200
201 __asm__ __volatile__ (
202 "sw $2,%0 \n\t"
203 "sw $3,%1 \n\t"
204 : "=m" (iret), "=m" (iret2) : );
205 register float fret asm("$f0");
206 register double dret asm("$f0");
207
208 switch( eReturnType )
209 {
210 case typelib_TypeClass_HYPER:
211 case typelib_TypeClass_UNSIGNED_HYPER:
212 ((long*)pRegisterReturn)[1] = iret2; // fall through
213 case typelib_TypeClass_LONG:
214 case typelib_TypeClass_UNSIGNED_LONG:
215 case typelib_TypeClass_ENUM:
216 ((long*)pRegisterReturn)[0] = iret;
217 break;
218 case typelib_TypeClass_CHAR:
219 case typelib_TypeClass_SHORT:
220 case typelib_TypeClass_UNSIGNED_SHORT:
221 *(unsigned short*)pRegisterReturn = (unsigned short)iret;
222 break;
223 case typelib_TypeClass_BOOLEAN:
224 case typelib_TypeClass_BYTE:
225 *(unsigned char*)pRegisterReturn = (unsigned char)iret;
226 break;
227 case typelib_TypeClass_FLOAT:
228 *(float*)pRegisterReturn = fret;
229 break;
230 case typelib_TypeClass_DOUBLE:
231 *(double*)pRegisterReturn = dret;
232 break;
233 default:
234 break;
235 }
236 }
237
238
239 //==================================================================================================
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)240 static void cpp_call(
241 bridges::cpp_uno::shared::UnoInterfaceProxy * pThis,
242 bridges::cpp_uno::shared::VtableSlot aVtableSlot,
243 typelib_TypeDescriptionReference * pReturnTypeRef,
244 sal_Int32 nParams, typelib_MethodParameter * pParams,
245 void * pUnoReturn, void * pUnoArgs[], uno_Any ** ppUnoExc )
246 {
247 // max space for: [complex ret ptr], values|ptr ...
248 char * pCppStack =
249 (char *)alloca( sizeof(sal_Int32) + ((nParams+2) * sizeof(sal_Int64)) );
250 char * pCppStackStart = pCppStack;
251
252 // need to know parameter types for callVirtualMethod so generate a signature string
253 char * pParamType = (char *) alloca(nParams+2);
254 char * pPT = pParamType;
255
256 #ifdef BRDEBUG
257 fprintf(stderr,"in cpp_call\n");
258 #endif
259
260 // return
261 typelib_TypeDescription * pReturnTypeDescr = 0;
262 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
263 // OSL_ENSURE( pReturnTypeDescr, "### expected return type description!" );
264
265 void * pCppReturn = 0; // if != 0 && != pUnoReturn, needs reconversion
266
267 if (pReturnTypeDescr)
268 {
269 if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr ))
270 {
271 pCppReturn = pUnoReturn; // direct way for simple types
272 }
273 else
274 {
275 // complex return via ptr
276 pCppReturn = *(void **)pCppStack =
277 (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
278 ? alloca( pReturnTypeDescr->nSize ): pUnoReturn); // direct way
279 *pPT++ = 'I'; //signify that a complex return type on stack
280 pCppStack += sizeof(void *);
281 }
282 }
283 // push this
284 void* pAdjustedThisPtr = reinterpret_cast< void **>(pThis->getCppI()) + aVtableSlot.offset;
285 *(void**)pCppStack = pAdjustedThisPtr;
286 pCppStack += sizeof( void* );
287 *pPT++ = 'I';
288
289 // stack space
290 // OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" );
291 // args
292 void ** pCppArgs = (void **)alloca( 3 * sizeof(void *) * nParams );
293 // indizes of values this have to be converted (interface conversion cpp<=>uno)
294 sal_Int32 * pTempIndizes = (sal_Int32 *)(pCppArgs + nParams);
295 // type descriptions for reconversions
296 typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pCppArgs + (2 * nParams));
297
298 sal_Int32 nTempIndizes = 0;
299
300 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
301 {
302 const typelib_MethodParameter & rParam = pParams[nPos];
303 typelib_TypeDescription * pParamTypeDescr = 0;
304 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
305
306 if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
307 {
308 uno_copyAndConvertData( pCppArgs[nPos] = pCppStack, pUnoArgs[nPos], pParamTypeDescr,
309 pThis->getBridge()->getUno2Cpp() );
310
311 switch (pParamTypeDescr->eTypeClass)
312 {
313
314 // we need to know type of each param so that we know whether to use
315 // gpr or fpr to pass in parameters:
316 // Key: I - int, long, pointer, etc means pass in gpr
317 // B - byte value passed in gpr
318 // S - short value passed in gpr
319 // F - float value pass in fpr
320 // D - double value pass in fpr
321 // H - long long int pass in proper pairs of gpr (3,4) (5,6), etc
322 // X - indicates end of parameter description string
323
324 case typelib_TypeClass_LONG:
325 case typelib_TypeClass_UNSIGNED_LONG:
326 case typelib_TypeClass_ENUM:
327 *pPT++ = 'I';
328 break;
329 case typelib_TypeClass_SHORT:
330 case typelib_TypeClass_CHAR:
331 case typelib_TypeClass_UNSIGNED_SHORT:
332 *pPT++ = 'S';
333 break;
334 case typelib_TypeClass_BOOLEAN:
335 case typelib_TypeClass_BYTE:
336 *pPT++ = 'B';
337 break;
338 case typelib_TypeClass_FLOAT:
339 *pPT++ = 'F';
340 break;
341 case typelib_TypeClass_DOUBLE:
342 *pPT++ = 'D';
343 pCppStack += sizeof(sal_Int32); // extra long
344 break;
345 case typelib_TypeClass_HYPER:
346 case typelib_TypeClass_UNSIGNED_HYPER:
347 *pPT++ = 'H';
348 pCppStack += sizeof(sal_Int32); // extra long
349 break;
350 default:
351 break;
352 }
353
354 // no longer needed
355 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
356 }
357 else // ptr to complex value | ref
358 {
359 if (! rParam.bIn) // is pure out
360 {
361 // cpp out is constructed mem, uno out is not!
362 uno_constructData(
363 *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
364 pParamTypeDescr );
365 pTempIndizes[nTempIndizes] = nPos; // default constructed for cpp call
366 // will be released at reconversion
367 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
368 }
369 // is in/inout
370 else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
371 {
372 uno_copyAndConvertData(
373 *(void **)pCppStack = pCppArgs[nPos] = alloca( pParamTypeDescr->nSize ),
374 pUnoArgs[nPos], pParamTypeDescr,
375 pThis->getBridge()->getUno2Cpp() );
376
377 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
378 // will be released at reconversion
379 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
380 }
381 else // direct way
382 {
383 *(void **)pCppStack = pCppArgs[nPos] = pUnoArgs[nPos];
384 // no longer needed
385 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
386 }
387 // KBH: FIXME: is this the right way to pass these
388 *pPT++='I';
389 }
390 pCppStack += sizeof(sal_Int32); // standard parameter length
391 }
392
393 // terminate the signature string
394 *pPT++='X';
395 *pPT=0;
396
397 try
398 {
399 OSL_ENSURE( !( (pCppStack - pCppStackStart ) & 3), "UNALIGNED STACK !!! (Please DO panic)" );
400 callVirtualMethod(
401 pAdjustedThisPtr, aVtableSlot.index,
402 pCppReturn, pReturnTypeDescr->eTypeClass, pParamType,
403 (sal_Int32 *)pCppStackStart, (pCppStack - pCppStackStart) / sizeof(sal_Int32) );
404 // NO exception occured...
405 *ppUnoExc = 0;
406
407 // reconvert temporary params
408 for ( ; nTempIndizes--; )
409 {
410 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
411 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
412
413 if (pParams[nIndex].bIn)
414 {
415 if (pParams[nIndex].bOut) // inout
416 {
417 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 ); // destroy uno value
418 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
419 pThis->getBridge()->getCpp2Uno() );
420 }
421 }
422 else // pure out
423 {
424 uno_copyAndConvertData( pUnoArgs[nIndex], pCppArgs[nIndex], pParamTypeDescr,
425 pThis->getBridge()->getCpp2Uno() );
426 }
427 // destroy temp cpp param => cpp: every param was constructed
428 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
429
430 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
431 }
432 // return value
433 if (pCppReturn && pUnoReturn != pCppReturn)
434 {
435 uno_copyAndConvertData( pUnoReturn, pCppReturn, pReturnTypeDescr,
436 pThis->getBridge()->getCpp2Uno() );
437 uno_destructData( pCppReturn, pReturnTypeDescr, cpp_release );
438 }
439 }
440 catch (...)
441 {
442 // fill uno exception
443 fillUnoException( CPPU_CURRENT_NAMESPACE::__cxa_get_globals()->caughtExceptions,
444 *ppUnoExc, pThis->getBridge()->getCpp2Uno() );
445
446 // temporary params
447 for ( ; nTempIndizes--; )
448 {
449 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
450 // destroy temp cpp param => cpp: every param was constructed
451 uno_destructData( pCppArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], cpp_release );
452 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
453 }
454 // return type
455 if (pReturnTypeDescr)
456 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
457 }
458 }
459
460 }
461
462
463 namespace bridges { namespace cpp_uno { namespace shared {
464
465 //==================================================================================================
unoInterfaceProxyDispatch(uno_Interface * pUnoI,const typelib_TypeDescription * pMemberDescr,void * pReturn,void * pArgs[],uno_Any ** ppException)466 void unoInterfaceProxyDispatch(
467 uno_Interface * pUnoI, const typelib_TypeDescription * pMemberDescr,
468 void * pReturn, void * pArgs[], uno_Any ** ppException )
469 {
470 // is my surrogate
471 bridges::cpp_uno::shared::UnoInterfaceProxy * pThis
472 = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy *> (pUnoI);
473 //typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
474
475 #ifdef BRDEBUG
476 fprintf(stderr,"in dispatch\n");
477 #endif
478
479 switch (pMemberDescr->eTypeClass)
480 {
481 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
482 {
483
484 VtableSlot aVtableSlot(
485 getVtableSlot(
486 reinterpret_cast<
487 typelib_InterfaceAttributeTypeDescription const * >(
488 pMemberDescr)));
489
490 if (pReturn)
491 {
492 // dependent dispatch
493 cpp_call(
494 pThis, aVtableSlot,
495 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef,
496 0, 0, // no params
497 pReturn, pArgs, ppException );
498 }
499 else
500 {
501 // is SET
502 typelib_MethodParameter aParam;
503 aParam.pTypeRef =
504 ((typelib_InterfaceAttributeTypeDescription *)pMemberDescr)->pAttributeTypeRef;
505 aParam.bIn = sal_True;
506 aParam.bOut = sal_False;
507
508 typelib_TypeDescriptionReference * pReturnTypeRef = 0;
509 OUString aVoidName( RTL_CONSTASCII_USTRINGPARAM("void") );
510 typelib_typedescriptionreference_new(
511 &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
512
513 // dependent dispatch
514 aVtableSlot.index += 1; //get then set method
515 cpp_call(
516 pThis, aVtableSlot,
517 pReturnTypeRef,
518 1, &aParam,
519 pReturn, pArgs, ppException );
520
521 typelib_typedescriptionreference_release( pReturnTypeRef );
522 }
523
524 break;
525 }
526 case typelib_TypeClass_INTERFACE_METHOD:
527 {
528
529 VtableSlot aVtableSlot(
530 getVtableSlot(
531 reinterpret_cast<
532 typelib_InterfaceMethodTypeDescription const * >(
533 pMemberDescr)));
534 switch (aVtableSlot.index)
535 {
536 // standard calls
537 case 1: // acquire uno interface
538 (*pUnoI->acquire)( pUnoI );
539 *ppException = 0;
540 break;
541 case 2: // release uno interface
542 (*pUnoI->release)( pUnoI );
543 *ppException = 0;
544 break;
545 case 0: // queryInterface() opt
546 {
547 typelib_TypeDescription * pTD = 0;
548 TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pArgs[0] )->getTypeLibType() );
549 if (pTD)
550 {
551 uno_Interface * pInterface = 0;
552 (*pThis->pBridge->getUnoEnv()->getRegisteredInterface)(
553 pThis->pBridge->getUnoEnv(),
554 (void **)&pInterface, pThis->oid.pData, (typelib_InterfaceTypeDescription *)pTD );
555
556 if (pInterface)
557 {
558 ::uno_any_construct(
559 reinterpret_cast< uno_Any * >( pReturn ),
560 &pInterface, pTD, 0 );
561 (*pInterface->release)( pInterface );
562 TYPELIB_DANGER_RELEASE( pTD );
563 *ppException = 0;
564 break;
565 }
566 TYPELIB_DANGER_RELEASE( pTD );
567 }
568 } // else perform queryInterface()
569 default:
570 // dependent dispatch
571 cpp_call(
572 pThis, aVtableSlot,
573 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pReturnTypeRef,
574 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->nParams,
575 ((typelib_InterfaceMethodTypeDescription *)pMemberDescr)->pParams,
576 pReturn, pArgs, ppException );
577 }
578 break;
579 }
580 default:
581 {
582 ::com::sun::star::uno::RuntimeException aExc(
583 OUString( RTL_CONSTASCII_USTRINGPARAM("illegal member type description!") ),
584 ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() );
585
586 Type const & rExcType = ::getCppuType( &aExc );
587 // binary identical null reference
588 ::uno_type_any_construct( *ppException, &aExc, rExcType.getTypeLibType(), 0 );
589 }
590 }
591 }
592 }}}
593
594