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 #include <com/sun/star/uno/genfunc.hxx>
24 #include <typelib/typedescription.hxx>
25 #include <uno/data.h>
26 #include <osl/endian.h>
27 #include "bridges/cpp_uno/shared/bridge.hxx"
28 #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx"
29 #include "bridges/cpp_uno/shared/types.hxx"
30 #include "bridges/cpp_uno/shared/vtablefactory.hxx"
31 #include "share.hxx"
32
33 #include <stdio.h>
34 #include <string.h>
35
36 using namespace com::sun::star::uno;
37
38 //#define BRDEBUG
39
40 #ifdef BRDEBUG
41 #include <rtl/strbuf.hxx>
42 #include <rtl/ustrbuf.hxx>
43 #include <osl/diagnose.h>
44 #include <osl/mutex.hxx>
45 using namespace ::std;
46 using namespace ::osl;
47 using namespace ::rtl;
48 #endif
49 #include <sys/sysmips.h>
50
51 #ifdef OSL_BIGENDIAN
52 #define IS_BIG_ENDIAN 1
53 #else
54 #define IS_BIG_ENDIAN 0
55 #endif
56
57 using namespace ::com::sun::star::uno;
58
59 namespace
60 {
61
62 //==================================================================================================
cpp2uno_call(bridges::cpp_uno::shared::CppInterfaceProxy * pThis,const typelib_TypeDescription * pMemberTypeDescr,typelib_TypeDescriptionReference * pReturnTypeRef,sal_Int32 nParams,typelib_MethodParameter * pParams,void ** gpreg,void **,void ** ovrflw,sal_Int64 * pRegisterReturn)63 static typelib_TypeClass cpp2uno_call(
64 bridges::cpp_uno::shared::CppInterfaceProxy * pThis,
65 const typelib_TypeDescription * pMemberTypeDescr,
66 typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return
67 sal_Int32 nParams, typelib_MethodParameter * pParams,
68 void ** gpreg, void ** /*fpreg*/, void ** ovrflw,
69 sal_Int64 * pRegisterReturn /* space for register return */ )
70 {
71 /* Most MIPS ABIs view the arguments as a struct, of which the
72 first N words go in registers and the rest go on the stack. If I < N, the
73 Ith word might go in Ith integer argument register or the Ith
74 floating-point one. For these ABIs, we only need to remember the number
75 of words passed so far. We are interested only in o32 ABI,so it is the
76 case.
77 */
78 int nw = 0; // number of words used by arguments
79
80 #ifdef BRDEBUG
81 fprintf(stderr,"cpp2uno_call1\n");
82 #endif
83
84 /* C++ has [ret *] or this as the first arguments, so no arguments will
85 * be passed in floating-point registers?
86 */
87 //int int_seen = 0; // have we seen integer arguments?
88
89 void ** pCppStack; //temporary stack pointer
90
91 // gpreg: [ret *], this, [gpr params]
92 // fpreg: [fpr params]
93 // ovrflw: [gpr or fpr params (properly aligned)]
94
95 // return
96 typelib_TypeDescription * pReturnTypeDescr = 0;
97 if (pReturnTypeRef)
98 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
99
100 void * pUnoReturn = 0;
101 void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
102
103 if (pReturnTypeDescr)
104 {
105 if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr ))
106 {
107 pUnoReturn = pRegisterReturn; // direct way for simple types
108 #ifdef BRDEBUG
109 fprintf(stderr,"cpp2uno_call:simplereturn\n");
110 #endif
111 }
112 else // complex return via ptr (pCppReturn)
113 {
114 pCppReturn = *(void **)gpreg;
115 gpreg++;
116 nw++;
117
118 pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
119 ? alloca( pReturnTypeDescr->nSize )
120 : pCppReturn); // direct way
121 #ifdef BRDEBUG
122 fprintf(stderr,"cpp2uno_call:complexreturn\n");
123 #endif
124 }
125 }
126
127 // pop this
128 gpreg++;
129 nw++;
130
131 // stack space
132 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32), "### unexpected size!" );
133 // parameters
134 void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams );
135 void ** pCppArgs = pUnoArgs + nParams;
136 // indizes of values this have to be converted (interface conversion cpp<=>uno)
137 sal_Int32 * pTempIndizes = (sal_Int32 *)(pUnoArgs + (2 * nParams));
138 // type descriptions for reconversions
139 typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams));
140
141 sal_Int32 nTempIndizes = 0;
142
143 #ifdef BRDEBUG
144 fprintf(stderr,"cpp2uno_call:nParams=%d\n",nParams);
145 #endif
146
147 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
148 {
149 const typelib_MethodParameter & rParam = pParams[nPos];
150 typelib_TypeDescription * pParamTypeDescr = 0;
151 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
152
153 if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
154 // value
155 {
156
157 switch (pParamTypeDescr->eTypeClass)
158 {
159 case typelib_TypeClass_DOUBLE:
160 case typelib_TypeClass_HYPER:
161 case typelib_TypeClass_UNSIGNED_HYPER:
162 #ifdef BRDEBUG
163 fprintf(stderr,"cpp2uno_call:hyper=%d,%p\n",pParamTypeDescr->eTypeClass,gpreg[0]);
164 #endif
165 if (nw < 3) {
166 if (nw & 1) {
167 nw++;
168 gpreg++;
169 }
170 #ifdef BRDEBUG
171 fprintf(stderr,"cpp2uno_call:gpreg=%p,%p\n",gpreg[0],gpreg[1]);
172 #endif
173 pCppArgs[nPos] = gpreg;
174 pUnoArgs[nPos] = gpreg;
175 nw += 2;
176 gpreg += 2;
177 } else {
178 if (((long)ovrflw) & 4) ovrflw++;
179 #ifdef BRDEBUG
180 fprintf(stderr,"cpp2uno_call:overflw=%p,%p\n",ovrflw[0],ovrflw[1]);
181 #endif
182 pCppArgs[nPos] = ovrflw;
183 pUnoArgs[nPos] = ovrflw;
184 ovrflw += 2;
185 }
186 break;
187
188 case typelib_TypeClass_BYTE:
189 case typelib_TypeClass_BOOLEAN:
190 #ifdef BRDEBUG
191 fprintf(stderr,"cpp2uno_call:byte=%p,%p\n",gpreg[0],ovrflw[0]);
192 #endif
193 if (nw < 4) {
194 pCppArgs[nPos] = ((char *)gpreg + 3*IS_BIG_ENDIAN);
195 pUnoArgs[nPos] = ((char *)gpreg + 3*IS_BIG_ENDIAN);
196 nw++;
197 gpreg++;
198 } else {
199 pCppArgs[nPos] = ((char *)ovrflw + 3*IS_BIG_ENDIAN);
200 pUnoArgs[nPos] = ((char *)ovrflw + 3*IS_BIG_ENDIAN);
201 ovrflw++;
202 }
203 break;
204
205
206 case typelib_TypeClass_CHAR:
207 case typelib_TypeClass_SHORT:
208 case typelib_TypeClass_UNSIGNED_SHORT:
209 #ifdef BRDEBUG
210 fprintf(stderr,"cpp2uno_call:char=%p,%p\n",gpreg[0],ovrflw[0]);
211 #endif
212 if (nw < 4) {
213 pCppArgs[nPos] = ((char *)gpreg + 2*IS_BIG_ENDIAN);
214 pUnoArgs[nPos] = ((char *)gpreg + 2*IS_BIG_ENDIAN);
215 nw++;
216 gpreg++;
217 } else {
218 pCppArgs[nPos] = ((char *)ovrflw + 2*IS_BIG_ENDIAN);
219 pUnoArgs[nPos] = ((char *)ovrflw + 2*IS_BIG_ENDIAN);
220 ovrflw++;
221 }
222 break;
223
224
225 default:
226 #ifdef BRDEBUG
227 fprintf(stderr,"cpp2uno_call:def=%p,%p\n",gpreg[0],ovrflw[0]);
228 #endif
229 if (nw < 4) {
230 pCppArgs[nPos] = gpreg;
231 pUnoArgs[nPos] = gpreg;
232 nw++;
233 gpreg++;
234 } else {
235 pCppArgs[nPos] = ovrflw;
236 pUnoArgs[nPos] = ovrflw;
237 ovrflw++;
238 }
239 break;
240
241 }
242 // no longer needed
243 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
244 }
245 else // ptr to complex value | ref
246 {
247
248 #ifdef BRDEBUG
249 fprintf(stderr,"cpp2uno_call:ptr|ref\n");
250 #endif
251 if (nw < 4) {
252 pCppArgs[nPos] = *(void **)gpreg;
253 pCppStack = gpreg;
254 nw++;
255 gpreg++;
256 } else {
257 pCppArgs[nPos] = *(void **)ovrflw;
258 pCppStack = ovrflw;
259 ovrflw++;
260 }
261 #ifdef BRDEBUG
262 fprintf(stderr,"cpp2uno_call:pCppStack=%p\n",pCppStack);
263 #endif
264
265 if (! rParam.bIn) // is pure out
266 {
267 // uno out is unconstructed mem!
268 pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
269 pTempIndizes[nTempIndizes] = nPos;
270 // will be released at reconversion
271 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
272 }
273 // is in/inout
274 else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
275 {
276 uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
277 *(void **)pCppStack, pParamTypeDescr,
278 pThis->getBridge()->getCpp2Uno() );
279 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
280 // will be released at reconversion
281 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
282 #ifdef BRDEBUG
283 fprintf(stderr,"cpp2uno_call:related to interface,%p,%d,pUnoargs[%d]=%p\n",*(void**)pCppStack,pParamTypeDescr->nSize,nPos,pUnoArgs[nPos]);
284 #endif
285 }
286 else // direct way
287 {
288 pUnoArgs[nPos] = *(void **)pCppStack;
289 #ifdef BRDEBUG
290 fprintf(stderr,"cpp2uno_call:direct,pUnoArgs[%d]=%p\n",nPos,pUnoArgs[nPos]);
291 #endif
292 // no longer needed
293 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
294 }
295 }
296 }
297 #ifdef BRDEBUG
298 fprintf(stderr,"cpp2uno_call2,%p,unoargs=%p\n",pThis->getUnoI()->pDispatcher,pUnoArgs);
299 #endif
300
301 // ExceptionHolder
302 uno_Any aUnoExc; // Any will be constructed by callee
303 uno_Any * pUnoExc = &aUnoExc;
304
305 // invoke uno dispatch call
306 (*pThis->getUnoI()->pDispatcher)( pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
307 #ifdef BRDEBUG
308 fprintf(stderr,"cpp2uno_call2,after dispatch\n");
309 #endif
310
311 // in case an exception occured...
312 if (pUnoExc)
313 {
314 // destruct temporary in/inout params
315 for ( ; nTempIndizes--; )
316 {
317 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
318
319 if (pParams[nIndex].bIn) // is in/inout => was constructed
320 uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndizes], 0 );
321 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
322 }
323 if (pReturnTypeDescr)
324 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
325
326 CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc, pThis->getBridge()->getUno2Cpp() );
327 // has to destruct the any
328 // is here for dummy
329 return typelib_TypeClass_VOID;
330 }
331 else // else no exception occured...
332 {
333 // temporary params
334 for ( ; nTempIndizes--; )
335 {
336 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
337 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndizes];
338
339 if (pParams[nIndex].bOut) // inout/out
340 {
341 // convert and assign
342 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
343 uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
344 pThis->getBridge()->getUno2Cpp() );
345 }
346 // destroy temp uno param
347 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
348
349 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
350 }
351 // return
352 if (pCppReturn) // has complex return
353 {
354 if (pUnoReturn != pCppReturn) // needs reconversion
355 {
356 uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
357 pThis->getBridge()->getUno2Cpp() );
358 // destroy temp uno return
359 uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
360 }
361 // complex return ptr is set to return reg
362 *(void **)pRegisterReturn = pCppReturn;
363 }
364 if (pReturnTypeDescr)
365 {
366 typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
367 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
368 return eRet;
369 }
370 else
371 return typelib_TypeClass_VOID;
372 }
373 }
374
375
376 //==================================================================================================
cpp_mediate(sal_Int32 nFunctionIndex,sal_Int32 nVtableOffset,void ** gpreg,void ** fpreg,void ** ovrflw,sal_Int64 * pRegisterReturn)377 static typelib_TypeClass cpp_mediate(
378 sal_Int32 nFunctionIndex,
379 sal_Int32 nVtableOffset,
380 void ** gpreg, void ** fpreg, void ** ovrflw,
381 sal_Int64 * pRegisterReturn /* space for register return */ )
382 {
383 OSL_ENSURE( sizeof(sal_Int32)==sizeof(void *), "### unexpected!" );
384
385 #ifdef BRDEBUG
386 fprintf(stderr,"cpp_mediate1 gp=%p,fp=%p,ov=%p\n",gpreg,fpreg,ovrflw);
387 fprintf(stderr,"gp=%x,%x,%x,%x\n",gpreg[0],gpreg[1],gpreg[2],gpreg[3]);
388 #endif
389
390 // gpreg: [ret *], this, [other gpr params]
391 // fpreg: [fpr params]
392 // ovrflw: [gpr or fpr params (properly aligned)]
393
394 void * pThis;
395 if (nFunctionIndex & 0x80000000 )
396 {
397 nFunctionIndex &= 0x7fffffff;
398 pThis = gpreg[1];
399 }
400 else
401 {
402 pThis = gpreg[0];
403 }
404 #ifdef BRDEBUG
405 fprintf(stderr,"cpp_mediate12,pThis=%p, nFunctionIndex=%d,nVtableOffset=%d\n",pThis,nFunctionIndex,nVtableOffset);
406 #endif
407
408 pThis = static_cast< char * >(pThis) - nVtableOffset;
409 bridges::cpp_uno::shared::CppInterfaceProxy * pCppI
410 = bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
411 pThis);
412 #ifdef BRDEBUG
413 fprintf(stderr,"cpp_mediate13,pCppI=%p\n",pCppI);
414 #endif
415
416 typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
417
418 #ifdef BRDEBUG
419 fprintf(stderr,"cpp_mediate2\n");
420 #endif
421 OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex, "### illegal vtable index!" );
422 if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
423 {
424 throw RuntimeException(
425 rtl::OUString::createFromAscii("illegal vtable index!"),
426 (XInterface *)pThis );
427 }
428
429 // determine called method
430 sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
431 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers, "### illegal member index!" );
432
433 TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
434
435 #ifdef BRDEBUG
436 fprintf(stderr,"cpp_mediate3\n");
437 OString cstr( OUStringToOString( aMemberDescr.get()->pTypeName, RTL_TEXTENCODING_ASCII_US ) );
438 fprintf( stderr, "calling %s, nFunctionIndex=%d\n", cstr.getStr(), nFunctionIndex );
439 #endif
440 typelib_TypeClass eRet;
441 switch (aMemberDescr.get()->eTypeClass)
442 {
443 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
444 {
445 #ifdef BRDEBUG
446 fprintf(stderr,"cpp_mediate4\n");
447 #endif
448 if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex)
449 {
450 // is GET method
451 eRet = cpp2uno_call(
452 pCppI, aMemberDescr.get(),
453 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef,
454 0, 0, // no params
455 gpreg, fpreg, ovrflw, pRegisterReturn );
456 }
457 else
458 {
459 // is SET method
460 typelib_MethodParameter aParam;
461 aParam.pTypeRef =
462 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef;
463 aParam.bIn = sal_True;
464 aParam.bOut = sal_False;
465
466 eRet = cpp2uno_call(
467 pCppI, aMemberDescr.get(),
468 0, // indicates void return
469 1, &aParam,
470 gpreg, fpreg, ovrflw, pRegisterReturn );
471 }
472 break;
473 }
474 case typelib_TypeClass_INTERFACE_METHOD:
475 {
476 #ifdef BRDEBUG
477 fprintf(stderr,"cpp_mediate5\n");
478 #endif
479 // is METHOD
480 switch (nFunctionIndex)
481 {
482 case 1: // acquire()
483 pCppI->acquireProxy(); // non virtual call!
484 eRet = typelib_TypeClass_VOID;
485 break;
486 case 2: // release()
487 #ifdef BRDEBUG
488 fprintf(stderr,"cpp_mediate51\n");
489 #endif
490 pCppI->releaseProxy(); // non virtual call!
491 eRet = typelib_TypeClass_VOID;
492 #ifdef BRDEBUG
493 fprintf(stderr,"cpp_mediate52\n");
494 #endif
495 break;
496 case 0: // queryInterface() opt
497 {
498 typelib_TypeDescription * pTD = 0;
499 TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( gpreg[2] )->getTypeLibType() );
500 if (pTD)
501 {
502 XInterface * pInterface = 0;
503 (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
504 pCppI->getBridge()->getCppEnv(),
505 (void **)&pInterface, pCppI->getOid().pData,
506 (typelib_InterfaceTypeDescription *)pTD );
507
508 if (pInterface)
509 {
510 ::uno_any_construct(
511 reinterpret_cast< uno_Any * >( gpreg[0] ),
512 &pInterface, pTD, cpp_acquire );
513 pInterface->release();
514 TYPELIB_DANGER_RELEASE( pTD );
515 *(void **)pRegisterReturn = gpreg[0];
516 eRet = typelib_TypeClass_ANY;
517 break;
518 }
519 TYPELIB_DANGER_RELEASE( pTD );
520 }
521 } // else perform queryInterface()
522 default:
523 eRet = cpp2uno_call(
524 pCppI, aMemberDescr.get(),
525 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef,
526 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams,
527 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams,
528 gpreg, fpreg, ovrflw, pRegisterReturn );
529 }
530 break;
531 }
532 default:
533 {
534 #ifdef BRDEBUG
535 fprintf(stderr,"cpp_mediate6\n");
536 #endif
537 throw RuntimeException(
538 rtl::OUString::createFromAscii("no member description found!"),
539 (XInterface *)pThis );
540 // is here for dummy
541 eRet = typelib_TypeClass_VOID;
542 }
543 }
544
545 return eRet;
546 }
547
548 //==================================================================================================
549 /**
550 * is called on incoming vtable calls
551 * (called by asm snippets)
552 */
553 // static void cpp_vtable_call( int nFunctionIndex, int nVtableOffset, void** gpregptr, void** fpregptr, void** ovrflw)
554 // static void cpp_vtable_call( int nFunctionIndex, int nVtableOffset, void** gpregptr, void** ovrflw)
cpp_vtable_call(void)555 static void cpp_vtable_call(void)
556 {
557 int nFunctionIndex;
558 int vTableOffset;
559 void** pCallStack;
560 void** ovrflw;
561
562 sal_Int32 gpreg[4];
563 double fpreg[2];
564
565 //memcpy( fpreg, fpregptr, 16);
566
567 volatile long nRegReturn[2];
568
569 __asm__( "sw $4, %0\n\t"
570 "sw $5, %1\n\t"
571 "sw $6, %2\n\t"
572 "sw $7, %3\n\t"
573 ::"m"(nFunctionIndex), "m"(vTableOffset), "m"(pCallStack), "m"(ovrflw) );
574
575 memcpy( gpreg, pCallStack, 16);
576
577 #ifdef BRDEBUG
578 fprintf(stderr,"in cpp_vtable_call nFunctionIndex is %d\n",nFunctionIndex);
579 fprintf(stderr,"in cpp_vtable_call nVtableOffset is %d\n",vTableOffset);
580 fprintf(stderr,"gp=%x,%x,%x,%x\n",gpreg[0],gpreg[1],gpreg[2],gpreg[3]);
581 #endif
582
583 //sal_Bool bComplex = nFunctionIndex & 0x80000000 ? sal_True : sal_False;
584
585 typelib_TypeClass aType =
586 cpp_mediate( nFunctionIndex, vTableOffset, (void**)gpreg, (void**)fpreg, ovrflw, (sal_Int64*)nRegReturn );
587
588 switch( aType )
589 {
590
591 // move return value into register space
592 // (will be loaded by machine code snippet)
593
594 case typelib_TypeClass_BOOLEAN:
595 case typelib_TypeClass_BYTE:
596 __asm__( "lbu $2,%0\n\t" : :
597 "m"(nRegReturn[0]) );
598 break;
599
600 case typelib_TypeClass_CHAR:
601 case typelib_TypeClass_UNSIGNED_SHORT:
602 __asm__( "lhu $2,%0\n\t" : :
603 "m"(nRegReturn[0]) );
604 break;
605
606 case typelib_TypeClass_SHORT:
607 __asm__( "lh $2,%0\n\t" : :
608 "m"(nRegReturn[0]) );
609 break;
610
611
612 case typelib_TypeClass_FLOAT:
613 __asm__( "lwc1 $f0,%0\n\t" : :
614 "m" (*((float*)nRegReturn)) );
615 break;
616
617 case typelib_TypeClass_DOUBLE:
618 { register double dret asm("$f0");
619 dret = (*((double*)nRegReturn)); }
620 break;
621
622 case typelib_TypeClass_HYPER:
623 case typelib_TypeClass_UNSIGNED_HYPER:
624 __asm__( "lw $3,%0\n\t" : :
625 "m"(nRegReturn[1]) ); // fall through
626
627 default:
628 __asm__( "lw $2,%0\n\t" : :
629 "m"(nRegReturn[0]) );
630 break;
631 }
632 }
633
634
635 int const codeSnippetSize = 56;
636
codeSnippet(unsigned char * code,sal_Int32 functionIndex,sal_Int32 vtableOffset,bool simpleRetType)637 unsigned char * codeSnippet( unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset,
638 bool simpleRetType)
639 {
640
641 #ifdef BRDEBUG
642 fprintf(stderr,"in codeSnippet functionIndex is %d\n", functionIndex);
643 fprintf(stderr,"in codeSnippet vtableOffset is %d\n", vtableOffset);
644 fflush(stderr);
645 #endif
646
647 if (! simpleRetType )
648 functionIndex |= 0x80000000;
649
650 unsigned long * p = (unsigned long *) code;
651
652 // OSL_ASSERT( sizeof (long) == 4 );
653 OSL_ASSERT((((unsigned long)code) & 0x3) == 0 ); //aligned to 4 otherwise a mistake
654
655 /* generate this code */
656 /*
657 #save regs into argument space required by mips abi
658 c: afa40000 sw a0,0(sp)
659 10: afa50004 sw a1,4(sp)
660 14: afa60008 sw a2,8(sp)
661 18: afa7000c sw a3,12(sp)
662 #a0=index
663 1c: 3c040000 lui a0,0x0
664 20: 34840000 ori a0,a0,0x0
665 #a1=offset
666 24: 3c050000 lui a1,0x0
667 28: 34a50000 ori a1,a1,0x0
668 #a2=gpregptr
669 2c: 27a60000 addiu a2,sp,0
670 #a3=ovrflw
671 30: 27a70010 addiu a3,sp,16
672 #load cpp_vtable_call addr
673 34: 3c190000 lui t9,0x0
674 38: 37390000 ori t9,t9,0
675 #jmp to the function,note: we don't use jalr, that will destroy $ra
676 #but be sure to use t9! gp calculation depends on it
677 3c: 03200008 jr t9
678 40: 00000000 nop
679
680 be careful, we use the argument space reserved by the caller to
681 write down regs. This can avoid the need to make use of arbitary far away
682 stack space or to allocate a function frame for this code snippet itself.
683 Since only functions with variable arguments will overwrite the space,
684 cpp_vtable_call should be safe.
685 ??? gcc seems change this behavior! cpp_vtable_call overwrite the space!
686 */
687
688 * p++ = 0xafa40000;
689 * p++ = 0xafa50004;
690 * p++ = 0xafa60008;
691 * p++ = 0xafa7000c;
692 * p++ = 0x3c040000 | ((functionIndex>>16) & 0x0000ffff);
693 * p++ = 0x34840000 | (functionIndex & 0x0000ffff);
694 * p++ = 0x3c050000 | ((vtableOffset>>16) & 0x0000ffff);
695 * p++ = 0x34a50000 | (vtableOffset & 0x0000ffff);
696 * p++ = 0x27a60000;
697 * p++ = 0x27a70010;
698 * p++ = 0x3c190000 | ((((unsigned long)cpp_vtable_call) >> 16) & 0x0000ffff);
699 * p++ = 0x37390000 | (((unsigned long)cpp_vtable_call) & 0x0000FFFF);
700 * p++ = 0x03200008;
701 * p++ = 0x00000000;
702 return (code + codeSnippetSize);
703
704 }
705
706
707 }
708
709
710 #define MIN_LINE_SIZE 32
711
flushCode(unsigned char const *,unsigned char const *)712 void bridges::cpp_uno::shared::VtableFactory::flushCode(unsigned char const * /*bptr*/, unsigned char const * /*eptr*/)
713 {
714 sysmips(FLUSH_CACHE,0,0,0);
715 }
716
717 struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; };
718
719 bridges::cpp_uno::shared::VtableFactory::Slot *
mapBlockToVtable(void * block)720 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
721 {
722 return static_cast< Slot * >(block) + 2;
723 }
724
725
getBlockSize(sal_Int32 slotCount)726 sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize(
727 sal_Int32 slotCount)
728 {
729 return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
730 }
731
732 bridges::cpp_uno::shared::VtableFactory::Slot *
initializeBlock(void * block,sal_Int32 slotCount)733 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
734 void * block, sal_Int32 slotCount)
735 {
736 Slot * slots = mapBlockToVtable(block);
737 slots[-2].fn = 0; //null
738 slots[-1].fn = 0; //destructor
739 return slots + slotCount;
740 }
741
addLocalFunctions(Slot ** slots,unsigned char * code,sal_PtrDiff writetoexecdiff,typelib_InterfaceTypeDescription const * type,sal_Int32 functionOffset,sal_Int32 functionCount,sal_Int32 vtableOffset)742 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
743 Slot ** slots, unsigned char * code, sal_PtrDiff writetoexecdiff,
744 typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
745 sal_Int32 functionCount, sal_Int32 vtableOffset)
746 {
747 (*slots) -= functionCount;
748 Slot * s = *slots;
749 #ifdef BRDEBUG
750 fprintf(stderr, "in addLocalFunctions functionOffset is %d\n",functionOffset);
751 fprintf(stderr, "in addLocalFunctions vtableOffset is %d\n",vtableOffset);
752 fprintf(stderr, "nMembers=%d\n",type->nMembers);
753 fflush(stderr);
754 #endif
755
756 for (sal_Int32 i = 0; i < type->nMembers; ++i) {
757 typelib_TypeDescription * member = 0;
758 TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
759 OSL_ASSERT(member != 0);
760 switch (member->eTypeClass) {
761 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
762 // Getter:
763 (s++)->fn = code + writetoexecdiff;
764 code = codeSnippet(
765 code, functionOffset++, vtableOffset,
766 bridges::cpp_uno::shared::isSimpleType(
767 reinterpret_cast<
768 typelib_InterfaceAttributeTypeDescription * >(
769 member)->pAttributeTypeRef));
770
771 // Setter:
772 if (!reinterpret_cast<
773 typelib_InterfaceAttributeTypeDescription * >(
774 member)->bReadOnly)
775 {
776 (s++)->fn = code + writetoexecdiff;
777 code = codeSnippet(code, functionOffset++, vtableOffset, true);
778 }
779 break;
780
781 case typelib_TypeClass_INTERFACE_METHOD:
782 (s++)->fn = code + writetoexecdiff;
783 code = codeSnippet(
784 code, functionOffset++, vtableOffset,
785 bridges::cpp_uno::shared::isSimpleType(
786 reinterpret_cast<
787 typelib_InterfaceMethodTypeDescription * >(
788 member)->pReturnTypeRef));
789 break;
790
791 default:
792 OSL_ASSERT(false);
793 break;
794 }
795 TYPELIB_DANGER_RELEASE(member);
796 }
797 return code;
798 }
799
800