LibreOffice Module bridges (master)  1
gcc3_ios/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 #include <com/sun/star/uno/RuntimeException.hpp>
20 #include <sal/log.hxx>
21 #include <uno/data.h>
22 #include <typelib/typedescription.hxx>
23 #include "bridge.hxx"
24 #include "cppinterfaceproxy.hxx"
25 #include "types.hxx"
26 #include "vtablefactory.hxx"
27 #include "share.hxx"
28 
29 
30 
31 extern "C" int codeSnippets[];
32 const int nFunIndexes = 8;
33 const int nVtableOffsets = 4;
34 
35 
36 
37 using namespace ::com::sun::star::uno;
38 
39 namespace
40 {
41  static typelib_TypeClass cpp2uno_call(
43  const typelib_TypeDescription * pMemberTypeDescr,
44  typelib_TypeDescriptionReference * pReturnTypeRef,
45  sal_Int32 nParams,
46  typelib_MethodParameter * pParams,
47  void ** pCallStack,
48  sal_Int64 * pRegisterReturn /* space for register return */ )
49  {
50  // pCallStack: x8, lr, d0..d7, x0..x7, rest of params originally on stack
51  char *pTopStack = (char *)pCallStack;
52  char *pFloatRegs = pTopStack + 2;
53  char *pGPRegs = pTopStack + (2+8)*8;
54  char *pStackedArgs = pTopStack + (2+8+8)*8;
55 
56  int nGPR = 0;
57  int nFPR = 0;
58 
59  // return
60  typelib_TypeDescription * pReturnTypeDescr = 0;
61  if (pReturnTypeRef)
62  TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
63 
64  void * pUnoReturn = 0;
65  // complex return ptr: if != 0 && != pUnoReturn, reconversion need
66  void * pCppReturn = 0;
67 
68  if (pReturnTypeDescr)
69  {
70  if (!arm::return_in_x8(pReturnTypeRef))
71  pUnoReturn = pRegisterReturn; // direct way for simple types
72  else // complex return via x8
73  {
74  pCppReturn = pCallStack[0];
75 
77  pReturnTypeDescr )
78  ? alloca( pReturnTypeDescr->nSize )
79  : pCppReturn); // direct way
80  }
81  }
82 
83  // Skip 'this'
84  pGPRegs += 8;
85  nGPR++;
86 
87  // Parameters
88  void ** pUnoArgs = (void **)alloca( sizeof(void *) * nParams );
89  void ** pCppArgs = (void **)alloca( sizeof(void *) * nParams );
90 
91  // Indices of values this have to be converted (interface conversion
92  // cpp<=>uno)
93  int * pTempIndices = (sal_Int32 *)alloca( sizeof(int) * nParams);
94 
95  // Type descriptions for reconversions
96  typelib_TypeDescription ** ppTempParamTypeDescr = (typelib_TypeDescription **)alloca( sizeof(typelib_TypeDescription *) * nParams);
97 
98  int nTempIndices = 0;
99 
100  for ( int nPos = 0; nPos < nParams; ++nPos )
101  {
102  const typelib_MethodParameter & rParam = pParams[nPos];
103  typelib_TypeDescription * pParamTypeDescr = 0;
104  TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
105 
106  if (!rParam.bOut &&
107  bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
108  {
109  if (nFPR < 8 && (pParamTypeDescr->eTypeClass == typelib_TypeClass_FLOAT ||
110  pParamTypeDescr->eTypeClass == typelib_TypeClass_DOUBLE))
111  {
112  pCppArgs[nPos] = pUnoArgs[nPos] = pFloatRegs;
113  pFloatRegs += 8;
114  nFPR++;
115  }
116  else if (pParamTypeDescr->eTypeClass == typelib_TypeClass_FLOAT)
117  {
118  if ((pStackedArgs - pTopStack) % 4)
119  pStackedArgs += 4 - ((pStackedArgs - pTopStack) % 4);
120  pCppArgs[nPos] = pUnoArgs[nPos] = pStackedArgs;
121  pStackedArgs += 4;
122  }
123  else if (pParamTypeDescr->eTypeClass == typelib_TypeClass_DOUBLE)
124  {
125  if ((pStackedArgs - pTopStack) % 8)
126  pStackedArgs += 8 - ((pStackedArgs - pTopStack) % 8);
127  pCppArgs[nPos] = pUnoArgs[nPos] = pStackedArgs;
128  pStackedArgs += 8;
129  }
130  else if (nGPR < 8)
131  {
132  pCppArgs[nPos] = pUnoArgs[nPos] = pGPRegs;
133  pGPRegs += 8;
134  nGPR++;
135  }
136  else
137  switch (pParamTypeDescr->eTypeClass)
138  {
139  case typelib_TypeClass_HYPER:
140  case typelib_TypeClass_UNSIGNED_HYPER:
141  if ((pStackedArgs - pTopStack) % 8)
142  pStackedArgs += 8 - ((pStackedArgs - pTopStack) % 8);
143  pCppArgs[nPos] = pUnoArgs[nPos] = pStackedArgs;
144  pStackedArgs += 8;
145  break;
146  case typelib_TypeClass_ENUM:
147  case typelib_TypeClass_LONG:
148  case typelib_TypeClass_UNSIGNED_LONG:
149  if ((pStackedArgs - pTopStack) % 4)
150  pStackedArgs += 4 - ((pStackedArgs - pTopStack) % 4);
151  pCppArgs[nPos] = pUnoArgs[nPos] = pStackedArgs;
152  pStackedArgs += 4;
153  break;
154  case typelib_TypeClass_CHAR:
155  case typelib_TypeClass_SHORT:
156  case typelib_TypeClass_UNSIGNED_SHORT:
157  if ((pStackedArgs - pTopStack) % 2)
158  pStackedArgs += 1;
159  pCppArgs[nPos] = pUnoArgs[nPos] = pStackedArgs;
160  pStackedArgs += 2;
161  break;
162  case typelib_TypeClass_BOOLEAN:
163  case typelib_TypeClass_BYTE:
164  pCppArgs[nPos] = pUnoArgs[nPos] = pStackedArgs;
165  pStackedArgs += 1;
166  break;
167  default:
168  assert(!"should not happen");
169  break;
170  }
171  // no longer needed
172  TYPELIB_DANGER_RELEASE( pParamTypeDescr );
173  }
174  else // ptr to complex value | ref
175  {
176  if (nGPR < 8)
177  {
178  pCppArgs[nPos] = *(void **)pGPRegs;
179  pGPRegs += 8;
180  }
181  else
182  {
183  if ((pStackedArgs - pTopStack) % 8)
184  pStackedArgs += 8 - ((pStackedArgs - pTopStack) % 8);
185  pCppArgs[nPos] = pStackedArgs;
186  pStackedArgs += 8;
187  }
188 
189  if (! rParam.bIn) // is pure out
190  {
191  // uno out is unconstructed mem!
192  pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
193  pTempIndices[nTempIndices] = nPos;
194  // will be released at reconversion
195  ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
196  }
197  // is in/inout
198  else if (bridges::cpp_uno::shared::relatesToInterfaceType( pParamTypeDescr ))
199  {
200  uno_copyAndConvertData( pUnoArgs[nPos] =
201  alloca( pParamTypeDescr->nSize ),
202  pCppArgs[nPos], pParamTypeDescr,
203  pThis->getBridge()->getCpp2Uno() );
204  pTempIndices[nTempIndices] = nPos; // has to be reconverted
205  // will be released at reconversion
206  ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
207  }
208  else // direct way
209  {
210  pUnoArgs[nPos] = pCppArgs[nPos];
211  // no longer needed
212  TYPELIB_DANGER_RELEASE( pParamTypeDescr );
213  }
214  }
215  }
216 
217  // ExceptionHolder
218  uno_Any aUnoExc; // Any will be constructed by callee
219  uno_Any * pUnoExc = &aUnoExc;
220 
221  // invoke uno dispatch call
222  (*pThis->getUnoI()->pDispatcher)(
223  pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
224 
225  // in case an exception occurred...
226  if (pUnoExc)
227  {
228  // destruct temporary in/inout params
229  for ( ; nTempIndices--; )
230  {
231  int nIndex = pTempIndices[nTempIndices];
232 
233  if (pParams[nIndex].bIn) // is in/inout => was constructed
234  uno_destructData( pUnoArgs[nIndex],
235  ppTempParamTypeDescr[nTempIndices], 0 );
236  TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
237  }
238  if (pReturnTypeDescr)
239  TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
240 
242  pThis->getBridge()->getUno2Cpp() ); // has to destruct the any
243  // is here for dummy
244  return typelib_TypeClass_VOID;
245  }
246  else // else no exception occurred...
247  {
248  // temporary params
249  for ( ; nTempIndices--; )
250  {
251  int nIndex = pTempIndices[nTempIndices];
252  typelib_TypeDescription * pParamTypeDescr =
253  ppTempParamTypeDescr[nTempIndices];
254 
255  if (pParams[nIndex].bOut) // inout/out
256  {
257  // convert and assign
258  uno_destructData( pCppArgs[nIndex], pParamTypeDescr,
259  cpp_release );
260  uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex],
261  pParamTypeDescr, pThis->getBridge()->getUno2Cpp() );
262  }
263  // destroy temp uno param
264  uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, 0 );
265 
266  TYPELIB_DANGER_RELEASE( pParamTypeDescr );
267  }
268  // return
269  if (pCppReturn) // has complex return
270  {
271  if (pUnoReturn != pCppReturn) // needs reconversion
272  {
273  uno_copyAndConvertData( pCppReturn, pUnoReturn,
274  pReturnTypeDescr, pThis->getBridge()->getUno2Cpp() );
275  // destroy temp uno return
276  uno_destructData( pUnoReturn, pReturnTypeDescr, 0 );
277  }
278  *(void **)pRegisterReturn = pCppReturn;
279  }
280  if (pReturnTypeDescr)
281  {
282  typelib_TypeClass eRet =
283  (typelib_TypeClass)pReturnTypeDescr->eTypeClass;
284  TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
285  return eRet;
286  }
287  else
288  return typelib_TypeClass_VOID;
289  }
290  }
291 
292 
293  static void cpp_mediate(sal_Int32 nFunctionIndex,
294  sal_Int32 nVtableOffset,
295  void ** pCallStack)
296  {
297  sal_Int64 nRegReturn;
298  sal_Int64 *pRegisterReturn = &nRegReturn;
299 
300  // pCallStack: x8, lr, d0..d7, x0..x7, rest of params originally on stack
301  // _this_ ptr is patched cppu_XInterfaceProxy object
302  void *pThis = pCallStack[2 + 8];
303 
304  pThis = static_cast< char * >(pThis) - nVtableOffset;
307  pThis);
308 
309  typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
310 
311  // determine called method
312  assert( nFunctionIndex < pTypeDescr->nMapFunctionIndexToMemberIndex );
313 
314  if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
315  {
316  throw RuntimeException( "illegal vtable index!", (XInterface *)pCppI );
317  }
318 
319  sal_Int32 nMemberPos =
320  pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
321  assert( nMemberPos < pTypeDescr->nAllMembers );
322 
323  TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
324 
325  typelib_TypeClass eRet;
326  switch (aMemberDescr.get()->eTypeClass)
327  {
328  case typelib_TypeClass_INTERFACE_ATTRIBUTE:
329  {
330  if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] ==
331  nFunctionIndex)
332  {
333  // is GET method
334  eRet = cpp2uno_call(
335  pCppI, aMemberDescr.get(),
336  ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef,
337  0, 0, // no params
338  pCallStack, pRegisterReturn );
339  }
340  else
341  {
342  // is SET method
343  typelib_MethodParameter aParam;
344  aParam.pTypeRef =
345  ((typelib_InterfaceAttributeTypeDescription *)aMemberDescr.get())->pAttributeTypeRef;
346  aParam.bIn = sal_True;
347  aParam.bOut = sal_False;
348 
349  eRet = cpp2uno_call(
350  pCppI, aMemberDescr.get(),
351  0, // indicates void return
352  1, &aParam,
353  pCallStack, pRegisterReturn );
354  }
355  break;
356  }
357  case typelib_TypeClass_INTERFACE_METHOD:
358  {
359  // is METHOD
360  switch (nFunctionIndex)
361  {
362  case 1: // acquire()
363  pCppI->acquireProxy(); // non virtual call!
364  eRet = typelib_TypeClass_VOID;
365  break;
366  case 2: // release()
367  pCppI->releaseProxy(); // non virtual call!
368  eRet = typelib_TypeClass_VOID;
369  break;
370  case 0: // queryInterface() opt
371  {
372  typelib_TypeDescription * pTD = 0;
373  TYPELIB_DANGER_GET(&pTD,
374  reinterpret_cast<Type *>(pCallStack[2])->getTypeLibType());
375  if (pTD)
376  {
377  XInterface * pInterface = 0;
378  (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
379  pCppI->getBridge()->getCppEnv(),
380  (void **)&pInterface, pCppI->getOid().pData,
381  (typelib_InterfaceTypeDescription *)pTD );
382 
383  if (pInterface)
384  {
385  ::uno_any_construct(
386  reinterpret_cast< uno_Any * >( pCallStack[0] ),
387  &pInterface, pTD, cpp_acquire );
388  pInterface->release();
389  TYPELIB_DANGER_RELEASE( pTD );
390  *(void **)pRegisterReturn = pCallStack[0];
391  eRet = typelib_TypeClass_ANY;
392  break;
393  }
394  TYPELIB_DANGER_RELEASE( pTD );
395  }
396  } // else perform queryInterface()
397  [[fallthrough]];
398  default:
399  eRet = cpp2uno_call(
400  pCppI, aMemberDescr.get(),
401  ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pReturnTypeRef,
402  ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->nParams,
403  ((typelib_InterfaceMethodTypeDescription *)aMemberDescr.get())->pParams,
404  pCallStack, pRegisterReturn );
405  }
406  break;
407  }
408  default:
409  {
410  throw RuntimeException( "no member description found!", (XInterface *)pCppI );
411  }
412  }
413 
414  (void)eRet;
415  return;
416  }
417 }
418 
424 extern "C" void cpp_vtable_call( sal_Int32 func, sal_Int32 offset,
425  void **pStack )
426 {
427  cpp_mediate(func, offset, pStack);
428 }
429 
430 namespace
431 {
432  unsigned char *codeSnippet(const typelib_InterfaceTypeDescription *type,
433  const typelib_TypeDescription *member,
434  sal_Int32 functionIndex,
435  sal_Int32 vtableOffset)
436  {
437  // For now temporarily assert when we get here. The intent is
438  // that we won't need the code snippets at all on iOS.
439  assert(false);
440 
441  assert(functionIndex < nFunIndexes);
442  if (!(functionIndex < nFunIndexes))
443  return NULL;
444 
445  assert(vtableOffset < nVtableOffsets);
446  if (!(vtableOffset < nVtableOffsets))
447  return NULL;
448 
449  // The codeSnippets table is indexed by functionIndex and vtableOffset
450 
451  int index = functionIndex*nVtableOffsets + vtableOffset;
452  unsigned char *result = ((unsigned char *) &codeSnippets) + codeSnippets[index];
453 
454  SAL_INFO( "bridges", "codeSnippet(" << OUString(type->aBase.pTypeName) << "::" << OUString(member->pTypeName) << "): [" << functionIndex << "," << vtableOffset << "]=" << (void *) result << " (" << std::hex << ((int*)result)[0] << "," << ((int*)result)[1] << "," << ((int*)result)[2] << "," << ((int*)result)[3] << ")");
455 
456  return result;
457  }
458 }
459 
461 
464 {
465  return static_cast< Slot * >(block) + 2;
466 }
467 
469  sal_Int32 slotCount)
470 {
471  return (slotCount + 2) * sizeof (Slot);
472 }
473 
476  void * block, sal_Int32 slotCount, sal_Int32,
477  typelib_InterfaceTypeDescription *)
478 {
479  Slot * slots = mapBlockToVtable(block);
480  slots[-2].fn = 0;
481  slots[-1].fn = 0;
482  return slots + slotCount;
483 }
484 
486  Slot ** slots,
487  unsigned char * code,
488  typelib_InterfaceTypeDescription const * type,
489  sal_Int32 functionOffset,
490  sal_Int32 functionCount,
491  sal_Int32 vtableOffset)
492 {
493  (*slots) -= functionCount;
494  Slot * s = *slots;
495  for (sal_Int32 i = 0; i < type->nMembers; ++i)
496  {
497  typelib_TypeDescription * member = 0;
498  TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
499  assert(member != 0);
500  switch (member->eTypeClass)
501  {
502  case typelib_TypeClass_INTERFACE_ATTRIBUTE:
503  {
504  typelib_InterfaceAttributeTypeDescription *pAttrTD =
505  reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>( member );
506 
507  // Getter:
508  (s++)->fn = codeSnippet( type, member, functionOffset++, vtableOffset );
509 
510  // Setter:
511  if (!pAttrTD->bReadOnly)
512  {
513  (s++)->fn = codeSnippet( type, member, functionOffset++, vtableOffset );
514  }
515  break;
516  }
517  case typelib_TypeClass_INTERFACE_METHOD:
518  {
519  (s++)->fn = codeSnippet( type, member, functionOffset++, vtableOffset );
520  break;
521  }
522  default:
523  assert(false);
524  break;
525  }
526  TYPELIB_DANGER_RELEASE(member);
527  }
528  return code;
529 }
530 
531 
532 
534  unsigned char const *, unsigned char const *)
535 {
536  // No dynamic code generation so nothing to flush
537 }
538 
539 
540 /* 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.
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
return NULL
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)
const int nFunIndexes
bool return_in_x8(typelib_TypeDescriptionReference *pTypeRef)
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()
int codeSnippets[]
tuple index
struct _typelib_TypeDescription typelib_TypeDescription
Definition: msvc/except.hxx:52
uno_Mapping * getCpp2Uno()
Definition: bridge.hxx:72
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)
#define SAL_INFO(area, stream)
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.
const int nVtableOffsets
Any result
static CppInterfaceProxy * castInterfaceToProxy(void *pInterface)
sal_uInt16 nPos
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo