LibreOffice Module bridges (master)  1
gcc3_solaris_intel/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 
21 #include <sal/alloca.h>
22 #include <strings.h>
23 
24 #include <com/sun/star/uno/genfunc.hxx>
25 #include "com/sun/star/uno/RuntimeException.hpp"
26 #include <sal/log.hxx>
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 using namespace ::com::sun::star::uno;
38 
39 namespace
40 {
41 
42 static typelib_TypeClass cpp2uno_call(
44  const typelib_TypeDescription * pMemberTypeDescr,
45  typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return
46  sal_Int32 nParams, typelib_MethodParameter * pParams,
47  void ** pCallStack,
48  sal_Int64 * pRegisterReturn /* space for register return */ )
49 {
50  // pCallStack: ret, [return ptr], this, params
51  char * pCppStack = (char *)(pCallStack +1);
52 
53  // return
54  typelib_TypeDescription * pReturnTypeDescr = 0;
55  if (pReturnTypeRef)
56  TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
57 
58  void * pUnoReturn = 0;
59  void * pCppReturn = 0; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
60 
61  if (pReturnTypeDescr)
62  {
63  if (bridges::cpp_uno::shared::isSimpleType( pReturnTypeDescr ))
64  {
65  pUnoReturn = pRegisterReturn; // direct way for simple types
66  }
67  else // complex return via ptr (pCppReturn)
68  {
69  pCppReturn = *(void **)pCppStack;
70  pCppStack += sizeof(void *);
71 
73  pReturnTypeDescr )
74  ? alloca( pReturnTypeDescr->nSize )
75  : pCppReturn); // direct way
76  }
77  }
78  // pop this
79  pCppStack += sizeof( void* );
80 
81  // stack space
82  static_assert(sizeof(void *) == sizeof(sal_Int32), "### unexpected size!");
83  // parameters
84  void ** pUnoArgs = (void **)alloca( 4 * sizeof(void *) * nParams );
85  void ** pCppArgs = pUnoArgs + nParams;
86  // indices of values this have to be converted (interface conversion cpp<=>uno)
87  sal_Int32 * pTempIndices = (sal_Int32 *)(pUnoArgs + (2 * nParams));
88  // type descriptions for reconversions
89  typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)(pUnoArgs + (3 * nParams));
90 
91  sal_Int32 nTempIndices = 0;
92 
93  for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
94  {
95  const typelib_MethodParameter & rParam = pParams[nPos];
96  typelib_TypeDescription * pParamTypeDescr = 0;
97  TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
98 
99  if (!rParam.bOut
100  && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
101  // value
102  {
103  pCppArgs[nPos] = pCppStack;
104  pUnoArgs[nPos] = pCppStack;
105  switch (pParamTypeDescr->eTypeClass)
106  {
107  case typelib_TypeClass_HYPER:
108  case typelib_TypeClass_UNSIGNED_HYPER:
109  case typelib_TypeClass_DOUBLE:
110  pCppStack += sizeof(sal_Int32); // extra long
111  }
112  // no longer needed
113  TYPELIB_DANGER_RELEASE( pParamTypeDescr );
114  }
115  else // ptr to complex value | ref
116  {
117  pCppArgs[nPos] = *(void **)pCppStack;
118 
119  if (! rParam.bIn) // is pure out
120  {
121  // uno out is unconstructed mem!
122  pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
123  pTempIndices[nTempIndices] = nPos;
124  // will be released at reconversion
125  ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
126  }
127  // is in/inout
129  pParamTypeDescr ))
130  {
131  uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
132  *(void **)pCppStack, pParamTypeDescr,
133  pThis->getBridge()->getCpp2Uno() );
134  pTempIndices[nTempIndices] = nPos; // has to be reconverted
135  // will be released at reconversion
136  ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
137  }
138  else // direct way
139  {
140  pUnoArgs[nPos] = *(void **)pCppStack;
141  // no longer needed
142  TYPELIB_DANGER_RELEASE( pParamTypeDescr );
143  }
144  }
145  pCppStack += sizeof(sal_Int32); // standard parameter length
146  }
147 
148  // ExceptionHolder
149  uno_Any aUnoExc; // Any will be constructed by callee
150  uno_Any * pUnoExc = &aUnoExc;
151 
152  // invoke uno dispatch call
153  (*pThis->getUnoI()->pDispatcher)(
154  pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
155 
156  // in case an exception occurred...
157  if (pUnoExc)
158  {
159  // destruct temporary in/inout params
160  for ( ; nTempIndices--; )
161  {
162  sal_Int32 nIndex = pTempIndices[nTempIndices];
163 
164  if (pParams[nIndex].bIn) // is in/inout => was constructed
165  uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndices], 0 );
166  TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
167  }
168  if (pReturnTypeDescr)
169  TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
170 
172  &aUnoExc, pThis->getBridge()->getUno2Cpp() );
173  // has to destruct the any
174  // is here for dummy
175  return typelib_TypeClass_VOID;
176  }
177  else // else no exception occurred...
178  {
179  // temporary params
180  for ( ; nTempIndices--; )
181  {
182  sal_Int32 nIndex = pTempIndices[nTempIndices];
183  typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
184 
185  if (pParams[nIndex].bOut) // inout/out
186  {
187  // convert and assign
188  uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
189  uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
190  pThis->getBridge()->getUno2Cpp() );
191  }
192  // destroy temp uno param
193  uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
194 
195  TYPELIB_DANGER_RELEASE( pParamTypeDescr );
196  }
197  // return
198  if (pCppReturn) // has complex return
199  {
200  if (pUnoReturn != pCppReturn) // needs reconversion
201  {
202  uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
203  pThis->getBridge()->getUno2Cpp() );
204  // destroy temp uno return
205  uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
206  }
207  // complex return ptr is set to eax
208  *(void **)pRegisterReturn = pCppReturn;
209  }
210  if (pReturnTypeDescr)
211  {
212  typelib_TypeClass eRet = (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
213  TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
214  return eRet;
215  }
216  else
217  return typelib_TypeClass_VOID;
218  }
219 }
220 
221 
222 static typelib_TypeClass cpp_mediate(
223  sal_Int32 nFunctionIndex,
224  sal_Int32 nVtableOffset,
225  void ** pCallStack,
226  sal_Int64 * pRegisterReturn /* space for register return */ )
227 {
228  static_assert(sizeof(sal_Int32)==sizeof(void *), "### unexpected!");
229 
230  // pCallStack: ret adr, [ret *], this, params
231  void * pThis;
232  if( nFunctionIndex & 0x80000000 )
233  {
234  nFunctionIndex &= 0x7fffffff;
235  pThis = pCallStack[2];
236  }
237  else
238  {
239  pThis = pCallStack[1];
240  }
241  pThis = static_cast< char * >(pThis) - nVtableOffset;
244  pThis);
245 
246  typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
247 
248  if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
249  {
250  SAL_WARN(
251  "bridges",
252  "illegal " << OUString::unacquired(&pTypeDescr->aBase.pTypeName)
253  << " vtable index " << nFunctionIndex << "/"
254  << pTypeDescr->nMapFunctionIndexToMemberIndex);
255  throw RuntimeException(
256  ("illegal " + OUString::unacquired(&pTypeDescr->aBase.pTypeName)
257  + " vtable index " + OUString::number(nFunctionIndex) + "/"
258  + OUString::number(pTypeDescr->nMapFunctionIndexToMemberIndex)),
259  (XInterface *)pThis);
260  }
261 
262  // determine called method
263  sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
264  assert(nMemberPos < pTypeDescr->nAllMembers);
265 
266  TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
267 
268  typelib_TypeClass eRet;
269  switch (aMemberDescr.get()->eTypeClass)
270  {
271  case typelib_TypeClass_INTERFACE_ATTRIBUTE:
272  {
273  if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex)
274  {
275  // is GET method
276  eRet = cpp2uno_call(
277  pCppI, aMemberDescr.get(),
278  ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef,
279  0, 0, // no params
280  pCallStack, pRegisterReturn );
281  }
282  else
283  {
284  // is SET method
285  typelib_MethodParameter aParam;
286  aParam.pTypeRef =
287  ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef;
288  aParam.bIn = sal_True;
289  aParam.bOut = sal_False;
290 
291  eRet = cpp2uno_call(
292  pCppI, aMemberDescr.get(),
293  0, // indicates void return
294  1, &aParam,
295  pCallStack, pRegisterReturn );
296  }
297  break;
298  }
299  case typelib_TypeClass_INTERFACE_METHOD:
300  {
301  // is METHOD
302  switch (nFunctionIndex)
303  {
304  case 1: // acquire()
305  pCppI->acquireProxy(); // non virtual call!
306  eRet = typelib_TypeClass_VOID;
307  break;
308  case 2: // release()
309  pCppI->releaseProxy(); // non virtual call!
310  eRet = typelib_TypeClass_VOID;
311  break;
312  case 0: // queryInterface() opt
313  {
314  typelib_TypeDescription * pTD = 0;
315  TYPELIB_DANGER_GET( &pTD, reinterpret_cast< Type * >( pCallStack[3] )->getTypeLibType() );
316  if (pTD)
317  {
318  XInterface * pInterface = 0;
319  (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
320  pCppI->getBridge()->getCppEnv(),
321  (void **)&pInterface, pCppI->getOid().pData,
322  (typelib_InterfaceTypeDescription *)pTD );
323 
324  if (pInterface)
325  {
326  ::uno_any_construct(
327  reinterpret_cast< uno_Any * >( pCallStack[1] ),
328  &pInterface, pTD, cpp_acquire );
329  pInterface->release();
330  TYPELIB_DANGER_RELEASE( pTD );
331  *(void **)pRegisterReturn = pCallStack[1];
332  eRet = typelib_TypeClass_ANY;
333  break;
334  }
335  TYPELIB_DANGER_RELEASE( pTD );
336  }
337  } // else perform queryInterface()
338  default:
339  eRet = cpp2uno_call(
340  pCppI, aMemberDescr.get(),
341  ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef,
342  ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams,
343  ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams,
344  pCallStack, pRegisterReturn );
345  }
346  break;
347  }
348  default:
349  {
350  throw RuntimeException( "no member description found!", (XInterface *)pThis );
351  }
352  }
353 
354  return eRet;
355 }
356 
361 static void __attribute__((noinline,regparm(3))) cpp_vtable_call(
362  int nFunctionIndex, int nVtableOffset, void** pCallStack )
363 {
364  volatile long nRegReturn[2];
365  typelib_TypeClass aType = cpp_mediate(
366  nFunctionIndex, nVtableOffset, pCallStack, (sal_Int64*)nRegReturn );
367 
368  switch( aType )
369  {
370  case typelib_TypeClass_HYPER:
371  case typelib_TypeClass_UNSIGNED_HYPER:
372  __asm__( "movl %1, %%edx\n\t"
373  "movl %0, %%eax\n"
374  : : "m"(nRegReturn[0]), "m"(nRegReturn[1]) );
375  break;
376  case typelib_TypeClass_FLOAT:
377  __asm__( "flds %0\n\t"
378  "fstp %%st(0)\n\t"
379  "flds %0\n"
380  : : "m"(*(float *)nRegReturn) );
381  break;
382  case typelib_TypeClass_DOUBLE:
383  __asm__( "fldl %0\n\t"
384  "fstp %%st(0)\n\t"
385  "fldl %0\n"
386  : : "m"(*(double *)nRegReturn) );
387  break;
388 // case typelib_TypeClass_UNSIGNED_SHORT:
389 // case typelib_TypeClass_SHORT:
390 // __asm__( "movswl %0, %%eax\n"
391 // : : "m"(nRegReturn) );
392 // break;
393  default:
394  __asm__( "movl %0, %%eax\n"
395  : : "m"(nRegReturn[0]) );
396  break;
397  }
398 }
399 
400 
401 int const codeSnippetSize = 20;
402 
403 unsigned char * codeSnippet(
404  unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset,
405  bool simpleRetType)
406 {
407  if (!simpleRetType) {
408  functionIndex |= 0x80000000;
409  }
410  unsigned char * p = code;
411  static_assert(sizeof (sal_Int32) == 4, "boo");
412  // mov function_index, %eax:
413  *p++ = 0xB8;
414  *reinterpret_cast< sal_Int32 * >(p) = functionIndex;
415  p += sizeof (sal_Int32);
416  // mov vtable_offset, %edx:
417  *p++ = 0xBA;
418  *reinterpret_cast< sal_Int32 * >(p) = vtableOffset;
419  p += sizeof (sal_Int32);
420  // mov %esp, %ecx:
421  *p++ = 0x89;
422  *p++ = 0xE1;
423  // jmp cpp_vtable_call:
424  *p++ = 0xE9;
425  *reinterpret_cast< sal_Int32 * >(p)
426  = ((unsigned char *) cpp_vtable_call) - p - sizeof (sal_Int32);
427  p += sizeof (sal_Int32);
428  assert(p - code <= codeSnippetSize);
429  return code + codeSnippetSize;
430 }
431 
432 }
433 
435 
438 {
439  return static_cast< Slot * >(block) + 2;
440 }
441 
443  sal_Int32 slotCount)
444 {
445  return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
446 }
447 
450  void * block, sal_Int32 slotCount, sal_Int32,
451  typelib_InterfaceTypeDescription *)
452 {
453  Slot * slots = mapBlockToVtable(block);
454  slots[-2].fn = 0;
455  slots[-1].fn = 0;
456  return slots + slotCount;
457 }
458 
460  Slot ** slots, unsigned char * code,
461  typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
462  sal_Int32 functionCount, sal_Int32 vtableOffset)
463 {
464  (*slots) -= functionCount;
465  Slot * s = *slots;
466  for (sal_Int32 i = 0; i < type->nMembers; ++i) {
467  typelib_TypeDescription * member = 0;
468  TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
469  assert(member != 0);
470  switch (member->eTypeClass) {
471  case typelib_TypeClass_INTERFACE_ATTRIBUTE:
472  // Getter:
473  (s++)->fn = code;
474  code = codeSnippet(
475  code, functionOffset++, vtableOffset,
477  reinterpret_cast<
478  typelib_InterfaceAttributeTypeDescription * >(
479  member)->pAttributeTypeRef));
480  // Setter:
481  if (!reinterpret_cast<
482  typelib_InterfaceAttributeTypeDescription * >(
483  member)->bReadOnly)
484  {
485  (s++)->fn = code;
486  code = codeSnippet(code, functionOffset++, vtableOffset, true);
487  }
488  break;
489 
490  case typelib_TypeClass_INTERFACE_METHOD:
491  (s++)->fn = code;
492  code = codeSnippet(
493  code, functionOffset++, vtableOffset,
495  reinterpret_cast<
496  typelib_InterfaceMethodTypeDescription * >(
497  member)->pReturnTypeRef));
498  break;
499 
500  default:
501  assert(false);
502  break;
503  }
504  TYPELIB_DANGER_RELEASE(member);
505  }
506  return code;
507 }
508 
510  unsigned char const *, unsigned char const *)
511 {}
512 
513 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
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
unsigned _Unwind_Word __attribute__((__mode__(__word__)))
Definition: unwind-cxx.h:45
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
register sal_uInt32 r28 __asm__("%r28")
void raiseException(uno_Any *pUnoExc, uno_Mapping *pUno2Cpp)
static int 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)
static unsigned char * codeSnippet(unsigned char *code, sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset, bool bHasHiddenParam)
void cpp_vtable_call(sal_Int32 func, sal_Int32 offset, void **pStack)
is called on incoming vtable calls (called by asm snippets)
#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