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 <hash_map>
26
27 #include <rtl/alloc.h>
28 #include <osl/mutex.hxx>
29
30 #include <com/sun/star/uno/genfunc.hxx>
31 #include "com/sun/star/uno/RuntimeException.hpp"
32 #include <uno/data.h>
33 #include <typelib/typedescription.hxx>
34
35 #include "bridges/cpp_uno/shared/bridge.hxx"
36 #include "bridges/cpp_uno/shared/cppinterfaceproxy.hxx"
37 #include "bridges/cpp_uno/shared/types.hxx"
38 #include "bridges/cpp_uno/shared/vtablefactory.hxx"
39
40 #include "share.hxx"
41
42 #include <dlfcn.h>
43
44
45 using namespace ::osl;
46 using namespace ::rtl;
47 using namespace ::com::sun::star::uno;
48
49 namespace
50 {
51
cpp2uno_call(bridges::cpp_uno::shared::CppInterfaceProxy * pThis,const typelib_TypeDescription * pMemberTypeDescr,typelib_TypeDescriptionReference * pReturnTypeRef,sal_Int32 nParams,typelib_MethodParameter * pParams,long r8,void ** pCallStack,sal_Int64 * pRegisterReturn)52 static typelib_TypeClass cpp2uno_call(
53 bridges::cpp_uno::shared::CppInterfaceProxy* pThis,
54 const typelib_TypeDescription * pMemberTypeDescr,
55 typelib_TypeDescriptionReference * pReturnTypeRef,
56 sal_Int32 nParams, typelib_MethodParameter * pParams,
57 long r8, void ** pCallStack,
58 sal_Int64 * pRegisterReturn /* space for register return */ )
59 {
60 // pCallStack: ret, [return ptr], this, params
61 char * pTopStack = (char *)(pCallStack + 0);
62 char * pCppStack = pTopStack;
63 #ifdef CMC_DEBUG
64 fprintf(stderr, "cpp2uno_call\n");
65 #endif
66 // return
67 typelib_TypeDescription * pReturnTypeDescr = 0;
68 if (pReturnTypeRef)
69 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
70
71 void * pUnoReturn = 0;
72 // complex return ptr: if != 0 && != pUnoReturn, reconversion need
73 void * pCppReturn = 0;
74
75 if (pReturnTypeDescr)
76 {
77 if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr ))
78 {
79 #ifdef CMC_DEBUG
80 fprintf(stderr, "simple return\n");
81 #endif
82 pUnoReturn = pRegisterReturn; // direct way for simple types
83 }
84 else // complex return via ptr (pCppReturn)
85 {
86 #ifdef CMC_DEBUG
87 fprintf(stderr, "complex return\n");
88 #endif
89 pCppReturn = (void *)r8;
90
91 pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
92 ? alloca( pReturnTypeDescr->nSize )
93 : pCppReturn); // direct way
94 }
95 }
96 // pop this
97 pCppStack += sizeof( void* );
98
99 // stack space
100 OSL_ENSURE( sizeof(void *) == sizeof(sal_Int32),
101 "### unexpected size!" );
102 // parameters
103 void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams );
104 void ** pCppArgs = pUnoArgs + nParams;
105 // indizes of values this have to be converted (interface conversion
106 // cpp<=>uno)
107 sal_Int32 * pTempIndizes = (sal_Int32 *)(pUnoArgs + (2 * nParams));
108 // type descriptions for reconversions
109 typelib_TypeDescription ** ppTempParamTypeDescr =
110 (typelib_TypeDescription **)(pUnoArgs + (3 * nParams));
111
112 sal_Int32 nTempIndizes = 0;
113
114 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
115 {
116 const typelib_MethodParameter & rParam = pParams[nPos];
117 typelib_TypeDescription * pParamTypeDescr = 0;
118 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
119
120 if (!rParam.bOut &&
121 bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
122 {
123 switch (pParamTypeDescr->eTypeClass)
124 {
125 case typelib_TypeClass_BYTE:
126 case typelib_TypeClass_BOOLEAN:
127 pCppArgs[nPos] = pCppStack + 3;
128 pUnoArgs[nPos] = pCppStack + 3;
129 break;
130 case typelib_TypeClass_CHAR:
131 case typelib_TypeClass_SHORT:
132 case typelib_TypeClass_UNSIGNED_SHORT:
133 pCppArgs[nPos] = pCppStack + 2;
134 pUnoArgs[nPos] = pCppStack + 2;
135 break;
136 case typelib_TypeClass_HYPER:
137 case typelib_TypeClass_UNSIGNED_HYPER:
138 case typelib_TypeClass_DOUBLE:
139 pCppArgs[nPos] = pCppStack;
140 pUnoArgs[nPos] = pCppStack;
141 pCppStack += sizeof(sal_Int32); // extra long
142 break;
143 default:
144 pCppArgs[nPos] = pCppStack;
145 pUnoArgs[nPos] = pCppStack;
146 break;
147 }
148 // no longer needed
149 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
150 }
151 else // ptr to complex value | ref
152 {
153 pCppArgs[nPos] = *(void **)pCppStack;
154
155 if (! rParam.bIn) // is pure out
156 {
157 // uno out is unconstructed mem!
158 pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
159 pTempIndizes[nTempIndizes] = nPos;
160 // will be released at reconversion
161 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
162 }
163 // is in/inout
164 else if (bridges::cpp_uno::shared::relatesToInterfaceType(
165 pParamTypeDescr ))
166 {
167 uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
168 *(void **)pCppStack, pParamTypeDescr,
169 pThis->getBridge()->getCpp2Uno() );
170 pTempIndizes[nTempIndizes] = nPos; // has to be reconverted
171 // will be released at reconversion
172 ppTempParamTypeDescr[nTempIndizes++] = pParamTypeDescr;
173 }
174 else // direct way
175 {
176 pUnoArgs[nPos] = *(void **)pCppStack;
177 // no longer needed
178 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
179 }
180 }
181 pCppStack += sizeof(sal_Int32); // standard parameter length
182 }
183
184 // ExceptionHolder
185 uno_Any aUnoExc; // Any will be constructed by callee
186 uno_Any * pUnoExc = &aUnoExc;
187
188 #ifdef CMC_DEBUG
189 fprintf(stderr, "before dispatch\n");
190 #endif
191 // invoke uno dispatch call
192 (*pThis->getUnoI()->pDispatcher)(
193 pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
194
195 #ifdef CMC_DEBUG
196 fprintf(stderr, "after dispatch\n");
197 #endif
198
199 // in case an exception occured...
200 if (pUnoExc)
201 {
202 // destruct temporary in/inout params
203 for ( ; nTempIndizes--; )
204 {
205 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
206
207 if (pParams[nIndex].bIn) // is in/inout => was constructed
208 uno_destructData( pUnoArgs[nIndex],
209 ppTempParamTypeDescr[nTempIndizes], 0 );
210 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndizes] );
211 }
212 if (pReturnTypeDescr)
213 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
214
215 CPPU_CURRENT_NAMESPACE::raiseException( &aUnoExc,
216 pThis->getBridge()->getUno2Cpp() ); // has to destruct the any
217 // is here for dummy
218 return typelib_TypeClass_VOID;
219 }
220 else // else no exception occured...
221 {
222 // temporary params
223 for ( ; nTempIndizes--; )
224 {
225 sal_Int32 nIndex = pTempIndizes[nTempIndizes];
226 typelib_TypeDescription * pParamTypeDescr =
227 ppTempParamTypeDescr[nTempIndizes];
228
229 if (pParams[nIndex].bOut) // inout/out
230 {
231 // convert and assign
232 uno_destructData( pCppArgs[nIndex], pParamTypeDescr,
233 cpp_release );
234 uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex],
235 pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
236 }
237 // destroy temp uno param
238 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
239
240 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
241 }
242 // return
243 if (pCppReturn) // has complex return
244 {
245 if (pUnoReturn != pCppReturn) // needs reconversion
246 {
247 uno_copyAndConvertData( pCppReturn, pUnoReturn,
248 pReturnTypeDescr, pThis->getBridge()->getUno2Cpp() );
249 // destroy temp uno return
250 uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
251 }
252 // complex return ptr is set to return reg
253 *(void **)pRegisterReturn = pCppReturn;
254 }
255 if (pReturnTypeDescr)
256 {
257 typelib_TypeClass eRet =
258 (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
259 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
260 return eRet;
261 }
262 else
263 return typelib_TypeClass_VOID;
264 }
265 }
266
267
268 //=====================================================================
cpp_mediate(sal_Int32 nFunctionIndex,sal_Int32 nVtableOffset,long sp,long r8,sal_Int64 * pRegisterReturn)269 static typelib_TypeClass cpp_mediate(
270 sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
271 long sp, long r8,
272 sal_Int64 * pRegisterReturn /* space for register return */ )
273 {
274 void ** pCallStack = (void**)(sp);
275 #ifdef CMC_DEBUG
276 fprintf(stderr, "cpp_mediate with\n");
277 fprintf(stderr, "%x %x\n", nFunctionIndex, nVtableOffset);
278 fprintf(stderr, "and %x %x\n", pCallStack, pRegisterReturn);
279 fprintf(stderr, "and %x %x\n", pCallStack[0], pCallStack[1]);
280 #endif
281 OSL_ENSURE( sizeof(sal_Int32)==sizeof(void *), "### unexpected!" );
282
283 void *pThis = pCallStack[0];
284
285 pThis = static_cast< char * >(pThis) - nVtableOffset;
286
287 bridges::cpp_uno::shared::CppInterfaceProxy * pCppI =
288 bridges::cpp_uno::shared::CppInterfaceProxy::castInterfaceToProxy(
289 pThis);
290
291 typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
292
293 OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex,
294 "### illegal vtable index!" );
295 if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
296 {
297 throw RuntimeException(
298 OUString::createFromAscii("illegal vtable index!"),
299 (XInterface *)pCppI );
300 }
301
302 // determine called method
303 OSL_ENSURE( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex,
304 "### illegal vtable index!" );
305 sal_Int32 nMemberPos =
306 pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
307 OSL_ENSURE( nMemberPos < pTypeDescr->nAllMembers,
308 "### illegal member index!" );
309
310 TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
311
312 typelib_TypeClass eRet;
313 switch (aMemberDescr.get()->eTypeClass)
314 {
315 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
316 {
317 if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] ==
318 nFunctionIndex)
319 {
320 // is GET method
321 eRet = cpp2uno_call(
322 pCppI, aMemberDescr.get(),
323 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef,
324 0, 0, // no params
325 r8, pCallStack, pRegisterReturn );
326 }
327 else
328 {
329 // is SET method
330 typelib_MethodParameter aParam;
331 aParam.pTypeRef =
332 ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef;
333 aParam.bIn = sal_True;
334 aParam.bOut = sal_False;
335
336 eRet = cpp2uno_call(
337 pCppI, aMemberDescr.get(),
338 0, // indicates void return
339 1, &aParam,
340 r8, pCallStack, pRegisterReturn );
341 }
342 break;
343 }
344 case typelib_TypeClass_INTERFACE_METHOD:
345 {
346 // is METHOD
347 switch (nFunctionIndex)
348 {
349 case 1: // acquire()
350 pCppI->acquireProxy(); // non virtual call!
351 eRet = typelib_TypeClass_VOID;
352 break;
353 case 2: // release()
354 pCppI->releaseProxy(); // non virtual call!
355 eRet = typelib_TypeClass_VOID;
356 break;
357 case 0: // queryInterface() opt
358 {
359 typelib_TypeDescription * pTD = 0;
360 TYPELIB_DANGER_GET(&pTD,
361 reinterpret_cast<Type *>(pCallStack[1])->getTypeLibType());
362 if (pTD)
363 {
364 XInterface * pInterface = 0;
365 (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
366 pCppI->getBridge()->getCppEnv(),
367 (void **)&pInterface, pCppI->getOid().pData,
368 (typelib_InterfaceTypeDescription *)pTD );
369
370 if (pInterface)
371 {
372 ::uno_any_construct(
373 reinterpret_cast< uno_Any * >( r8 ),
374 &pInterface, pTD, cpp_acquire );
375 pInterface->release();
376 TYPELIB_DANGER_RELEASE( pTD );
377 *(void **)pRegisterReturn = (void*)r8;
378 eRet = typelib_TypeClass_ANY;
379 break;
380 }
381 TYPELIB_DANGER_RELEASE( pTD );
382 }
383 } // else perform queryInterface()
384 default:
385 eRet = cpp2uno_call(
386 pCppI, aMemberDescr.get(),
387 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef,
388 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams,
389 ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams,
390 r8, pCallStack, pRegisterReturn );
391 }
392 break;
393 }
394 default:
395 {
396 throw RuntimeException(
397 OUString::createFromAscii("no member description found!"),
398 (XInterface *)pCppI );
399 // is here for dummy
400 eRet = typelib_TypeClass_VOID;
401 }
402 }
403
404 return eRet;
405 }
406 }
407
408 //=======================================================================
409 /**
410 * is called on incoming vtable calls
411 * (called by asm snippets)
412 */
413
cpp_vtable_call(long firstonstack)414 extern "C" sal_Int64 cpp_vtable_call( long firstonstack )
415 {
416 register long d0 asm("d0");
417 long functionIndex = d0;
418
419 register long a1 asm("a1");
420 long r8 = a1;
421
422 register long d1 asm("d1");
423 long vtableOffset = d1;
424
425 long sp = (long)&firstonstack;
426
427 sal_Int64 nRegReturn;
428 cpp_mediate( functionIndex, vtableOffset, sp, r8, &nRegReturn );
429 return nRegReturn;
430 }
431
432 namespace
433 {
434 const int codeSnippetSize = 20;
435
436 //some m68k info : http://www2.biglobe.ne.jp/~inaba/trampolines.html
437
codeSnippet(unsigned char * code,sal_Int32 functionIndex,sal_Int32 vtableOffset)438 unsigned char *codeSnippet(unsigned char* code, sal_Int32 functionIndex,
439 sal_Int32 vtableOffset)
440 {
441 unsigned char * p = code;
442 *(short *)&p[0] = 0x203C; //movel functionIndex,d0
443 *(long *)&p[2] = functionIndex;
444 *(short *)&p[6] = 0x223C; //movel functionIndex,d1
445 *(long *)&p[8] = vtableOffset;
446 *(short *)&p[12] = 0x4EF9; //jmp cpp_vtable_call
447 *(long *)&p[14] = (long)&cpp_vtable_call;
448 *(short *)&p[18] = 0x4E71; //nop
449 return code + codeSnippetSize;
450 }
451 }
452
453 struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; };
454
455 bridges::cpp_uno::shared::VtableFactory::Slot *
mapBlockToVtable(void * block)456 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block)
457 {
458 return static_cast< Slot * >(block) + 2;
459 }
460
getBlockSize(sal_Int32 slotCount)461 sal_Size bridges::cpp_uno::shared::VtableFactory::getBlockSize(
462 sal_Int32 slotCount)
463 {
464 return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
465 }
466
467 bridges::cpp_uno::shared::VtableFactory::Slot *
initializeBlock(void * block,sal_Int32 slotCount)468 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
469 void * block, sal_Int32 slotCount)
470 {
471 Slot * slots = mapBlockToVtable(block);
472 slots[-2].fn = 0;
473 slots[-1].fn = 0;
474 return slots + slotCount;
475 }
476
addLocalFunctions(Slot ** slots,unsigned char * code,sal_PtrDiff writetoexecdiff,typelib_InterfaceTypeDescription const * type,sal_Int32 functionOffset,sal_Int32 functionCount,sal_Int32 vtableOffset)477 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
478 Slot ** slots, unsigned char * code, sal_PtrDiff writetoexecdiff,
479 typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
480 sal_Int32 functionCount, sal_Int32 vtableOffset)
481 {
482 (*slots) -= functionCount;
483 Slot * s = *slots;
484 for (sal_Int32 i = 0; i < type->nMembers; ++i)
485 {
486 typelib_TypeDescription * member = 0;
487 TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
488 OSL_ASSERT(member != 0);
489 switch (member->eTypeClass)
490 {
491 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
492 // Getter:
493 (s++)->fn = code + writetoexecdiff;
494 code = codeSnippet(code, functionOffset++, vtableOffset);
495 // Setter:
496 if (!reinterpret_cast<
497 typelib_InterfaceAttributeTypeDescription * >(
498 member)->bReadOnly)
499 {
500 (s++)->fn = code + writetoexecdiff;
501 code = codeSnippet(code, functionOffset++, vtableOffset);
502 }
503 break;
504 case typelib_TypeClass_INTERFACE_METHOD:
505 {
506 (s++)->fn = code + writetoexecdiff;
507
508 typelib_InterfaceMethodTypeDescription *pMethodTD =
509 reinterpret_cast<
510 typelib_InterfaceMethodTypeDescription * >(member);
511
512 bool issimple = bridges::cpp_uno::shared::isSimpleType(
513 pMethodTD->pReturnTypeRef);
514
515 code = codeSnippet(code, functionOffset++, vtableOffset);
516 break;
517 }
518 default:
519 OSL_ASSERT(false);
520 break;
521 }
522 TYPELIB_DANGER_RELEASE(member);
523 }
524 return code;
525 }
526
flushCode(unsigned char const *,unsigned char const *)527 void bridges::cpp_uno::shared::VtableFactory::flushCode(
528 unsigned char const * /*beg*/, unsigned char const * /*end*/)
529 {
530 }
531
532 /* vi:set tabstop=4 shiftwidth=4 expandtab: */
533