LibreOffice Module bridges (master)  1
gcc3_linux_m68k/cpp2uno.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <malloc.h>
21 
22 #include <rtl/alloc.h>
23 #include <sal/log.hxx>
24 
25 #include <com/sun/star/uno/genfunc.hxx>
26 #include "com/sun/star/uno/RuntimeException.hpp"
27 #include <uno/data.h>
28 #include <typelib/typedescription.hxx>
29 
30 #include "bridge.hxx"
31 #include "cppinterfaceproxy.hxx"
32 #include "types.hxx"
33 #include "vtablefactory.hxx"
34 
35 #include "share.hxx"
36 
37 #include <dlfcn.h>
38 
39 
40 using namespace ::osl;
41 using namespace ::com::sun::star::uno;
42 
43 namespace
44 {
45 
46  static typelib_TypeClass cpp2uno_call(
48  const typelib_TypeDescription * pMemberTypeDescr,
49  typelib_TypeDescriptionReference * pReturnTypeRef,
50  sal_Int32 nParams, typelib_MethodParameter * pParams,
51  long r8, void ** pCallStack,
52  sal_Int64 * pRegisterReturn /* space for register return */ )
53  {
54  // pCallStack: ret, [return ptr], this, params
55  char * pTopStack = (char *)(pCallStack + 0);
56  char * pCppStack = pTopStack;
57 #if OSL_DEBUG_LEVEL > 2
58  fprintf(stderr, "cpp2uno_call\n");
59 #endif
60  // return
61  typelib_TypeDescription * pReturnTypeDescr = 0;
62  if (pReturnTypeRef)
63  TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
64 
65  void * pUnoReturn = 0;
66  // complex return ptr: if != 0 && != pUnoReturn, reconversion need
67  void * pCppReturn = 0;
68 
69  if (pReturnTypeDescr)
70  {
71  if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr ))
72  {
73 #if OSL_DEBUG_LEVEL > 2
74  fprintf(stderr, "simple return\n");
75 #endif
76  pUnoReturn = pRegisterReturn; // direct way for simple types
77  }
78  else // complex return via ptr (pCppReturn)
79  {
80 #if OSL_DEBUG_LEVEL > 2
81  fprintf(stderr, "complex return\n");
82 #endif
83  pCppReturn = (void *)r8;
84 
85  pUnoReturn = (bridges::cpp_uno::shared::relatesToInterfaceType( pReturnTypeDescr )
86  ? alloca( pReturnTypeDescr->nSize )
87  : pCppReturn); // direct way
88  }
89  }
90  // pop this
91  pCppStack += sizeof( void* );
92 
93  // stack space
94  static_assert( sizeof(void *) == sizeof(sal_Int32),
95  "### unexpected size!" );
96  // parameters
97  void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams );
98  void ** pCppArgs = pUnoArgs + nParams;
99  // indices of values this have to be converted (interface conversion
100  // cpp<=>uno)
101  sal_Int32 * pTempIndices = (sal_Int32 *)(pUnoArgs + (2 * nParams));
102  // type descriptions for reconversions
103  typelib_TypeDescription ** ppTempParamTypeDescr =
104  (typelib_TypeDescription **)(pUnoArgs + (3 * nParams));
105 
106  sal_Int32 nTempIndices = 0;
107 
108  for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
109  {
110  const typelib_MethodParameter & rParam = pParams[nPos];
111  typelib_TypeDescription * pParamTypeDescr = 0;
112  TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
113 
114  if (!rParam.bOut &&
115  bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
116  {
117  switch (pParamTypeDescr->eTypeClass)
118  {
119  case typelib_TypeClass_BYTE:
120  case typelib_TypeClass_BOOLEAN:
121  pCppArgs[nPos] = pCppStack + 3;
122  pUnoArgs[nPos] = pCppStack + 3;
123  break;
124  case typelib_TypeClass_CHAR:
125  case typelib_TypeClass_SHORT:
126  case typelib_TypeClass_UNSIGNED_SHORT:
127  pCppArgs[nPos] = pCppStack + 2;
128  pUnoArgs[nPos] = pCppStack + 2;
129  break;
130  case typelib_TypeClass_HYPER:
131  case typelib_TypeClass_UNSIGNED_HYPER:
132  case typelib_TypeClass_DOUBLE:
133  pCppArgs[nPos] = pCppStack;
134  pUnoArgs[nPos] = pCppStack;
135  pCppStack += sizeof(sal_Int32); // extra long
136  break;
137  default:
138  pCppArgs[nPos] = pCppStack;
139  pUnoArgs[nPos] = pCppStack;
140  break;
141  }
142  // no longer needed
143  TYPELIB_DANGER_RELEASE( pParamTypeDescr );
144  }
145  else // ptr to complex value | ref
146  {
147  pCppArgs[nPos] = *(void **)pCppStack;
148 
149  if (! rParam.bIn) // is pure out
150  {
151  // uno out is unconstructed mem!
152  pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
153  pTempIndices[nTempIndices] = nPos;
154  // will be released at reconversion
155  ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
156  }
157  // is in/inout
159  pParamTypeDescr ))
160  {
161  uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
162  *(void **)pCppStack, pParamTypeDescr,
163  pThis->getBridge()->getCpp2Uno() );
164  pTempIndices[nTempIndices] = nPos; // has to be reconverted
165  // will be released at reconversion
166  ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
167  }
168  else // direct way
169  {
170  pUnoArgs[nPos] = *(void **)pCppStack;
171  // no longer needed
172  TYPELIB_DANGER_RELEASE( pParamTypeDescr );
173  }
174  }
175  pCppStack += sizeof(sal_Int32); // standard parameter length
176  }
177 
178  // ExceptionHolder
179  uno_Any aUnoExc; // Any will be constructed by callee
180  uno_Any * pUnoExc = &aUnoExc;
181 
182 #if OSL_DEBUG_LEVEL > 2
183  fprintf(stderr, "before dispatch\n");
184 #endif
185  // invoke uno dispatch call
186  (*pThis->getUnoI()->pDispatcher)(
187  pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
188 
189 #if OSL_DEBUG_LEVEL > 2
190  fprintf(stderr, "after dispatch\n");
191 #endif
192 
193  // in case an exception occurred...
194  if (pUnoExc)
195  {
196  // destruct temporary in/inout params
197  for ( ; nTempIndices--; )
198  {
199  sal_Int32 nIndex = pTempIndices[nTempIndices];
200 
201  if (pParams[nIndex].bIn) // is in/inout => was constructed
202  uno_destructData( pUnoArgs[nIndex],
203  ppTempParamTypeDescr[nTempIndices], 0 );
204  TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
205  }
206  if (pReturnTypeDescr)
207  TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
208 
210  pThis->getBridge()->getUno2Cpp() ); // has to destruct the any
211  // is here for dummy
212  return typelib_TypeClass_VOID;
213  }
214  else // else no exception occurred...
215  {
216  // temporary params
217  for ( ; nTempIndices--; )
218  {
219  sal_Int32 nIndex = pTempIndices[nTempIndices];
220  typelib_TypeDescription * pParamTypeDescr =
221  ppTempParamTypeDescr[nTempIndices];
222 
223  if (pParams[nIndex].bOut) // inout/out
224  {
225  // convert and assign
226  uno_destructData( pCppArgs[nIndex], pParamTypeDescr,
227  cpp_release );
228  uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex],
229  pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
230  }
231  // destroy temp uno param
232  uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
233 
234  TYPELIB_DANGER_RELEASE( pParamTypeDescr );
235  }
236  // return
237  if (pCppReturn) // has complex return
238  {
239  if (pUnoReturn != pCppReturn) // needs reconversion
240  {
241  uno_copyAndConvertData( pCppReturn, pUnoReturn,
242  pReturnTypeDescr, pThis->getBridge()->getUno2Cpp() );
243  // destroy temp uno return
244  uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
245  }
246  // complex return ptr is set to return reg
247  *(void **)pRegisterReturn = pCppReturn;
248  }
249  if (pReturnTypeDescr)
250  {
251  typelib_TypeClass eRet =
252  (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
253  TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
254  return eRet;
255  }
256  else
257  return typelib_TypeClass_VOID;
258  }
259  }
260 
261 
262  static typelib_TypeClass cpp_mediate(
263  sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset,
264  long sp, long r8,
265  sal_Int64 * pRegisterReturn /* space for register return */ )
266  {
267  void ** pCallStack = (void**)(sp);
268 #if OSL_DEBUG_LEVEL > 2
269  fprintf(stderr, "cpp_mediate with\n");
270  fprintf(stderr, "%x %x\n", nFunctionIndex, nVtableOffset);
271  fprintf(stderr, "and %x %x\n", pCallStack, pRegisterReturn);
272  fprintf(stderr, "and %x %x\n", pCallStack[0], pCallStack[1]);
273 #endif
274  static_assert( sizeof(sal_Int32)==sizeof(void *), "### unexpected!" );
275 
276  void *pThis = pCallStack[0];
277 
278  pThis = static_cast< char * >(pThis) - nVtableOffset;
279 
282  pThis);
283 
284  typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
285 
286  if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
287  {
288  SAL_WARN(
289  "bridges",
290  "illegal " << OUString::unacquired(&pTypeDescr->aBase.pTypeName)
291  << " vtable index " << nFunctionIndex << "/"
292  << pTypeDescr->nMapFunctionIndexToMemberIndex);
293  throw RuntimeException(
294  ("illegal " + OUString::unacquired(&pTypeDescr->aBase.pTypeName)
295  + " vtable index " + OUString::number(nFunctionIndex) + "/"
296  + OUString::number(pTypeDescr->nMapFunctionIndexToMemberIndex)),
297  (XInterface *)pCppI);
298  }
299 
300  // determine called method
301  assert(nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex);
302  sal_Int32 nMemberPos =
303  pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
304  assert(nMemberPos < pTypeDescr->nAllMembers);
305 
306  TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
307 
308  typelib_TypeClass eRet;
309  switch (aMemberDescr.get()->eTypeClass)
310  {
311  case typelib_TypeClass_INTERFACE_ATTRIBUTE:
312  {
313  if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] ==
314  nFunctionIndex)
315  {
316  // is GET method
317  eRet = cpp2uno_call(
318  pCppI, aMemberDescr.get(),
319  ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef,
320  0, 0, // no params
321  r8, pCallStack, pRegisterReturn );
322  }
323  else
324  {
325  // is SET method
326  typelib_MethodParameter aParam;
327  aParam.pTypeRef =
328  ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef;
329  aParam.bIn = sal_True;
330  aParam.bOut = sal_False;
331 
332  eRet = cpp2uno_call(
333  pCppI, aMemberDescr.get(),
334  0, // indicates void return
335  1, &aParam,
336  r8, pCallStack, pRegisterReturn );
337  }
338  break;
339  }
340  case typelib_TypeClass_INTERFACE_METHOD:
341  {
342  // is METHOD
343  switch (nFunctionIndex)
344  {
345  case 1: // acquire()
346  pCppI->acquireProxy(); // non virtual call!
347  eRet = typelib_TypeClass_VOID;
348  break;
349  case 2: // release()
350  pCppI->releaseProxy(); // non virtual call!
351  eRet = typelib_TypeClass_VOID;
352  break;
353  case 0: // queryInterface() opt
354  {
355  typelib_TypeDescription * pTD = 0;
356  TYPELIB_DANGER_GET(&pTD,
357  reinterpret_cast<Type *>(pCallStack[1])->getTypeLibType());
358  if (pTD)
359  {
360  XInterface * pInterface = 0;
361  (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
362  pCppI->getBridge()->getCppEnv(),
363  (void **)&pInterface, pCppI->getOid().pData,
364  (typelib_InterfaceTypeDescription *)pTD );
365 
366  if (pInterface)
367  {
368  ::uno_any_construct(
369  reinterpret_cast< uno_Any * >( r8 ),
370  &pInterface, pTD, cpp_acquire );
371  pInterface->release();
372  TYPELIB_DANGER_RELEASE( pTD );
373  *(void **)pRegisterReturn = (void*)r8;
374  eRet = typelib_TypeClass_ANY;
375  break;
376  }
377  TYPELIB_DANGER_RELEASE( pTD );
378  }
379  } // else perform queryInterface()
380  default:
381  eRet = cpp2uno_call(
382  pCppI, aMemberDescr.get(),
383  ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef,
384  ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams,
385  ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams,
386  r8, pCallStack, pRegisterReturn );
387  }
388  break;
389  }
390  default:
391  {
392  throw RuntimeException( "no member description found!", (XInterface *)pCppI );
393  }
394  }
395 
396  return eRet;
397  }
398 }
399 
405 extern "C" sal_Int64 cpp_vtable_call( long firstonstack )
406 {
407  register long d0 asm("d0");
408  long functionIndex = d0;
409 
410  register long a1 asm("a1");
411  long r8 = a1;
412 
413  register long d1 asm("d1");
414  long vtableOffset = d1;
415 
416  long sp = (long)&firstonstack;
417 
418  sal_Int64 nRegReturn;
419  cpp_mediate( functionIndex, vtableOffset, sp, r8, &nRegReturn );
420  return nRegReturn;
421 }
422 
423 namespace
424 {
425  const int codeSnippetSize = 20;
426 
427  //some m68k info: http://www2.biglobe.ne.jp/~inaba/trampolines.html
428 
429  unsigned char *codeSnippet(unsigned char* code, sal_Int32 functionIndex,
430  sal_Int32 vtableOffset)
431  {
432  unsigned char * p = code;
433  *(short *)&p[0] = 0x203C; //movel functionIndex,d0
434  *(long *)&p[2] = functionIndex;
435  *(short *)&p[6] = 0x223C; //movel functionIndex,d1
436  *(long *)&p[8] = vtableOffset;
437  *(short *)&p[12] = 0x4EF9; //jmp cpp_vtable_call
438  *(long *)&p[14] = (long)&cpp_vtable_call;
439  *(short *)&p[18] = 0x4E71; //nop
440  return code + codeSnippetSize;
441  }
442 }
443 
445 
448 {
449  return static_cast< Slot * >(block) + 2;
450 }
451 
453  sal_Int32 slotCount)
454 {
455  return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
456 }
457 
460  void * block, sal_Int32 slotCount, sal_Int32,
461  typelib_InterfaceTypeDescription *)
462 {
463  Slot * slots = mapBlockToVtable(block);
464  slots[-2].fn = 0;
465  slots[-1].fn = 0;
466  return slots + slotCount;
467 }
468 
470  Slot ** slots, unsigned char * code, sal_PtrDiff writetoexecdiff,
471  typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
472  sal_Int32 functionCount, sal_Int32 vtableOffset)
473 {
474  (*slots) -= functionCount;
475  Slot * s = *slots;
476  for (sal_Int32 i = 0; i < type->nMembers; ++i)
477  {
478  typelib_TypeDescription * member = 0;
479  TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
480  assert(member != 0);
481  switch (member->eTypeClass)
482  {
483  case typelib_TypeClass_INTERFACE_ATTRIBUTE:
484  // Getter:
485  (s++)->fn = code + writetoexecdiff;
486  code = codeSnippet(code, functionOffset++, vtableOffset);
487  // Setter:
488  if (!reinterpret_cast<
489  typelib_InterfaceAttributeTypeDescription * >(
490  member)->bReadOnly)
491  {
492  (s++)->fn = code + writetoexecdiff;
493  code = codeSnippet(code, functionOffset++, vtableOffset);
494  }
495  break;
496  case typelib_TypeClass_INTERFACE_METHOD:
497  {
498  (s++)->fn = code + writetoexecdiff;
499 
500  typelib_InterfaceMethodTypeDescription *pMethodTD =
501  reinterpret_cast<
502  typelib_InterfaceMethodTypeDescription * >(member);
503 
504  code = codeSnippet(code, functionOffset++, vtableOffset);
505  break;
506  }
507  default:
508  assert(false);
509  break;
510  }
511  TYPELIB_DANGER_RELEASE(member);
512  }
513  return code;
514 }
515 
517  unsigned char const * /*beg*/, unsigned char const * /*end*/)
518 {
519 }
520 
521 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static typelib_TypeClass cpp2uno_call(bridges::cpp_uno::shared::CppInterfaceProxy *pThis, const typelib_TypeDescription *pMemberTypeDescr, typelib_TypeDescriptionReference *pReturnTypeRef, sal_Int32 nParams, typelib_MethodParameter *pParams, void **gpreg, void **fpreg, void **ovrflw, sal_uInt64 *pRegisterReturn)
sal_Int32 nIndex
void SAL_CALL uno_destructData(void *pValue, typelib_TypeDescription *pTypeDescr, uno_ReleaseFunc release) SAL_THROW_EXTERN_C()
bool isSimpleType(typelib_TypeClass typeClass)
Determines whether a type is a "simple" type (VOID, BOOLEAN, BYTE, SHORT, UNSIGNED SHORT...
Definition: types.cxx:28
static std::size_t getBlockSize(sal_Int32 slotCount)
Calculate the size of a raw vtable block.
const int codeSnippetSize
bool relatesToInterfaceType(typelib_TypeDescription const *type)
Determines whether a type relates to an interface type (is itself an interface type, or might contain entities of interface type).
Definition: types.cxx:41
static Slot * initializeBlock(void *block, sal_Int32 slotCount, sal_Int32 vtableNumber, typelib_InterfaceTypeDescription *type)
Initialize a raw vtable block.
typelib_TypeClass __cdecl cpp_mediate(void **pCallStack, const sal_Int32 nFunctionIndex, const sal_Int32 nVtableOffset, sal_Int64 *const pRegisterReturn)
static Slot * mapBlockToVtable(void *block)
Given a pointer to a block, turn it into a vtable pointer.
struct _uno_Any uno_Any
Definition: msvc/except.hxx:31
uno_Mapping * getUno2Cpp()
Definition: bridge.hxx:73
uno_ExtEnvironment * getCppEnv()
Definition: bridge.hxx:69
static unsigned char * addLocalFunctions(Slot **slots, unsigned char *code, sal_PtrDiff writetoexecdiff, typelib_InterfaceTypeDescription const *type, sal_Int32 functionOffset, sal_Int32 functionCount, sal_Int32 vtableOffset)
Fill the vtable slots corresponding to all local (i.e., not inherited) functions of a given interface...
typelib_InterfaceTypeDescription * getTypeDescr()
A cpp proxy wrapping a uno interface.
int i
#define sal_True
void SAL_CALL uno_copyAndConvertData(void *pDest, void *pSource, typelib_TypeDescription *pTypeDescr, uno_Mapping *mapping) SAL_THROW_EXTERN_C()
struct _typelib_TypeDescription typelib_TypeDescription
Definition: msvc/except.hxx:52
uno_Mapping * getCpp2Uno()
Definition: bridge.hxx:72
sal_Int64 cpp_vtable_call(long firstonstack)
is called on incoming vtable calls (called by asm snippets)
void raiseException(uno_Any *pUnoExc, uno_Mapping *pUno2Cpp)
static unsigned char * codeSnippet(unsigned char *code, sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset, bool bHasHiddenParam)
#define sal_False
static void flushCode(unsigned char const *begin, unsigned char const *end)
Flush all the generated code snippets of a vtable, on platforms that require it.
void * p
#define SAL_WARN(area, stream)
static CppInterfaceProxy * castInterfaceToProxy(void *pInterface)
sal_uInt16 nPos