LibreOffice Module bridges (master) 1
gcc3_linux_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/config.h>
22
23#include <typeinfo>
24
25#include <com/sun/star/uno/genfunc.hxx>
26#include <com/sun/star/uno/RuntimeException.hpp>
27#include <sal/log.hxx>
28#include <uno/data.h>
29#include <typelib/typedescription.hxx>
30
31#include <bridge.hxx>
32#include <cppinterfaceproxy.hxx>
33#include <types.hxx>
34#include <vtablefactory.hxx>
35
36#include "call.hxx"
37#include "share.hxx"
38
39using namespace ::com::sun::star::uno;
40
41namespace
42{
43
44void cpp2uno_call(
46 const typelib_TypeDescription * pMemberTypeDescr,
47 typelib_TypeDescriptionReference * pReturnTypeRef, // 0 indicates void return
48 sal_Int32 nParams, typelib_MethodParameter * pParams,
49 void ** pCallStack,
50 void * pReturnValue )
51{
52 // pCallStack: ret, [return ptr], this, params
53 char * pCppStack = reinterpret_cast<char *>(pCallStack +1);
54
55 // return
56 typelib_TypeDescription * pReturnTypeDescr = nullptr;
57 if (pReturnTypeRef)
58 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
59
60 void * pUnoReturn = nullptr;
61 void * pCppReturn = nullptr; // complex return ptr: if != 0 && != pUnoReturn, reconversion need
62
63 if (pReturnTypeDescr)
64 {
65 if (x86::isSimpleReturnType( pReturnTypeDescr ))
66 {
67 pUnoReturn = pReturnValue; // direct way for simple types
68 }
69 else // complex return via ptr (pCppReturn)
70 {
71 pCppReturn = *reinterpret_cast<void **>(pCppStack);
72 pCppStack += sizeof(void *);
73
75 pReturnTypeDescr )
76 ? alloca( pReturnTypeDescr->nSize )
77 : pCppReturn); // direct way
78 }
79 }
80 // pop this
81 pCppStack += sizeof( void* );
82
83 // stack space
84 static_assert(sizeof(void *) == sizeof(sal_Int32), "### unexpected size!");
85 // parameters
86 void ** pUnoArgs = static_cast<void **>(alloca( 4 * sizeof(void *) * nParams ));
87 void ** pCppArgs = pUnoArgs + nParams;
88 // indices of values this have to be converted (interface conversion cpp<=>uno)
89 sal_Int32 * pTempIndices = reinterpret_cast<sal_Int32 *>(pUnoArgs + (2 * nParams));
90 // type descriptions for reconversions
91 typelib_TypeDescription ** ppTempParamTypeDescr = reinterpret_cast<typelib_TypeDescription **>(pUnoArgs + (3 * nParams));
92
93 sal_Int32 nTempIndices = 0;
94
95 for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
96 {
97 const typelib_MethodParameter & rParam = pParams[nPos];
98 typelib_TypeDescription * pParamTypeDescr = nullptr;
99 TYPELIB_DANGER_GET( &pParamTypeDescr, rParam.pTypeRef );
100
101 if (!rParam.bOut
102 && bridges::cpp_uno::shared::isSimpleType( pParamTypeDescr ))
103 // value
104 {
105 pCppArgs[nPos] = pCppStack;
106 pUnoArgs[nPos] = pCppStack;
107 switch (pParamTypeDescr->eTypeClass)
108 {
109 case typelib_TypeClass_HYPER:
110 case typelib_TypeClass_UNSIGNED_HYPER:
111 case typelib_TypeClass_DOUBLE:
112 pCppStack += sizeof(sal_Int32); // extra long
113 break;
114 default:
115 break;
116 }
117 // no longer needed
118 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
119 }
120 else // ptr to complex value | ref
121 {
122 pCppArgs[nPos] = *reinterpret_cast<void **>(pCppStack);
123
124 if (! rParam.bIn) // is pure out
125 {
126 // uno out is unconstructed mem!
127 pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize );
128 pTempIndices[nTempIndices] = nPos;
129 // will be released at reconversion
130 ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
131 }
132 // is in/inout
134 pParamTypeDescr ))
135 {
136 uno_copyAndConvertData( pUnoArgs[nPos] = alloca( pParamTypeDescr->nSize ),
137 *reinterpret_cast<void **>(pCppStack), pParamTypeDescr,
138 pThis->getBridge()->getCpp2Uno() );
139 pTempIndices[nTempIndices] = nPos; // has to be reconverted
140 // will be released at reconversion
141 ppTempParamTypeDescr[nTempIndices++] = pParamTypeDescr;
142 }
143 else // direct way
144 {
145 pUnoArgs[nPos] = *reinterpret_cast<void **>(pCppStack);
146 // no longer needed
147 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
148 }
149 }
150 pCppStack += sizeof(sal_Int32); // standard parameter length
151 }
152
153 // ExceptionHolder
154 uno_Any aUnoExc; // Any will be constructed by callee
155 uno_Any * pUnoExc = &aUnoExc;
156
157 // invoke uno dispatch call
158 (*pThis->getUnoI()->pDispatcher)(
159 pThis->getUnoI(), pMemberTypeDescr, pUnoReturn, pUnoArgs, &pUnoExc );
160
161 // in case an exception occurred...
162 if (pUnoExc)
163 {
164 // destruct temporary in/inout params
165 for ( ; nTempIndices--; )
166 {
167 sal_Int32 nIndex = pTempIndices[nTempIndices];
168
169 if (pParams[nIndex].bIn) // is in/inout => was constructed
170 uno_destructData( pUnoArgs[nIndex], ppTempParamTypeDescr[nTempIndices], nullptr );
171 TYPELIB_DANGER_RELEASE( ppTempParamTypeDescr[nTempIndices] );
172 }
173 if (pReturnTypeDescr)
174 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
175
177 &aUnoExc, pThis->getBridge()->getUno2Cpp() );
178 // has to destruct the any
179 }
180 else // else no exception occurred...
181 {
182 // temporary params
183 for ( ; nTempIndices--; )
184 {
185 sal_Int32 nIndex = pTempIndices[nTempIndices];
186 typelib_TypeDescription * pParamTypeDescr = ppTempParamTypeDescr[nTempIndices];
187
188 if (pParams[nIndex].bOut) // inout/out
189 {
190 // convert and assign
191 uno_destructData( pCppArgs[nIndex], pParamTypeDescr, cpp_release );
192 uno_copyAndConvertData( pCppArgs[nIndex], pUnoArgs[nIndex], pParamTypeDescr,
193 pThis->getBridge()->getUno2Cpp() );
194 }
195 // destroy temp uno param
196 uno_destructData( pUnoArgs[nIndex], pParamTypeDescr, nullptr );
197
198 TYPELIB_DANGER_RELEASE( pParamTypeDescr );
199 }
200 // return
201 if (pCppReturn) // has complex return
202 {
203 if (pUnoReturn != pCppReturn) // needs reconversion
204 {
205 uno_copyAndConvertData( pCppReturn, pUnoReturn, pReturnTypeDescr,
206 pThis->getBridge()->getUno2Cpp() );
207 // destroy temp uno return
208 uno_destructData( pUnoReturn, pReturnTypeDescr, nullptr );
209 }
210 // complex return ptr is set to eax
211 *static_cast< void ** >(pReturnValue) = pCppReturn;
212 }
213 if (pReturnTypeDescr)
214 {
215 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
216 }
217 }
218}
219
220
221extern "C" void cpp_vtable_call(
222 int nFunctionIndex, int nVtableOffset, void** pCallStack,
223 void * pReturnValue )
224{
225 static_assert(sizeof(sal_Int32)==sizeof(void *), "### unexpected!");
226
227 // pCallStack: ret adr, [ret *], this, params
228 void * pThis;
229 if( nFunctionIndex & 0x80000000 )
230 {
231 nFunctionIndex &= 0x7fffffff;
232 pThis = pCallStack[2];
233 }
234 else
235 {
236 pThis = pCallStack[1];
237 }
238 pThis = static_cast< char * >(pThis) - nVtableOffset;
241 pThis);
242
243 typelib_InterfaceTypeDescription * pTypeDescr = pCppI->getTypeDescr();
244
245 if (nFunctionIndex >= pTypeDescr->nMapFunctionIndexToMemberIndex)
246 {
247 SAL_WARN(
248 "bridges",
249 "illegal " << OUString::unacquired(&pTypeDescr->aBase.pTypeName)
250 << " vtable index " << nFunctionIndex << "/"
251 << pTypeDescr->nMapFunctionIndexToMemberIndex);
252 throw RuntimeException(
253 ("illegal " + OUString::unacquired(&pTypeDescr->aBase.pTypeName)
254 + " vtable index " + OUString::number(nFunctionIndex) + "/"
255 + OUString::number(pTypeDescr->nMapFunctionIndexToMemberIndex)),
256 static_cast<XInterface *>(pThis));
257 }
258
259 // determine called method
260 sal_Int32 nMemberPos = pTypeDescr->pMapFunctionIndexToMemberIndex[nFunctionIndex];
261 assert(nMemberPos < pTypeDescr->nAllMembers);
262
263 TypeDescription aMemberDescr( pTypeDescr->ppAllMembers[nMemberPos] );
264
265 switch (aMemberDescr.get()->eTypeClass)
266 {
267 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
268 {
269 if (pTypeDescr->pMapMemberIndexToFunctionIndex[nMemberPos] == nFunctionIndex)
270 {
271 // is GET method
273 pCppI, aMemberDescr.get(),
274 reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>(aMemberDescr.get())->pAttributeTypeRef,
275 0, nullptr, // no params
276 pCallStack, pReturnValue );
277 }
278 else
279 {
280 // is SET method
281 typelib_MethodParameter aParam;
282 aParam.pTypeRef =
283 reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>(aMemberDescr.get())->pAttributeTypeRef;
284 aParam.bIn = true;
285 aParam.bOut = false;
286
288 pCppI, aMemberDescr.get(),
289 nullptr, // indicates void return
290 1, &aParam,
291 pCallStack, pReturnValue );
292 }
293 break;
294 }
295 case typelib_TypeClass_INTERFACE_METHOD:
296 {
297 // is METHOD
298 switch (nFunctionIndex)
299 {
300 case 1: // acquire()
301 pCppI->acquireProxy(); // non virtual call!
302 break;
303 case 2: // release()
304 pCppI->releaseProxy(); // non virtual call!
305 break;
306 case 0: // queryInterface() opt
307 {
308 typelib_TypeDescription * pTD = nullptr;
309 TYPELIB_DANGER_GET( &pTD, static_cast< Type * >( pCallStack[3] )->getTypeLibType() );
310 if (pTD)
311 {
312 XInterface * pInterface = nullptr;
313 (*pCppI->getBridge()->getCppEnv()->getRegisteredInterface)(
314 pCppI->getBridge()->getCppEnv(),
315 reinterpret_cast<void **>(&pInterface), pCppI->getOid().pData,
316 reinterpret_cast<typelib_InterfaceTypeDescription *>(pTD) );
317
318 if (pInterface)
319 {
320 ::uno_any_construct(
321 static_cast< uno_Any * >( pCallStack[1] ),
322 &pInterface, pTD, cpp_acquire );
323 pInterface->release();
324 TYPELIB_DANGER_RELEASE( pTD );
325 *static_cast< void ** >(pReturnValue) = pCallStack[1];
326 break;
327 }
328 TYPELIB_DANGER_RELEASE( pTD );
329 }
330 [[fallthrough]]; // else perform queryInterface()
331 }
332 default:
334 pCppI, aMemberDescr.get(),
335 reinterpret_cast<typelib_InterfaceMethodTypeDescription *>(aMemberDescr.get())->pReturnTypeRef,
336 reinterpret_cast<typelib_InterfaceMethodTypeDescription *>(aMemberDescr.get())->nParams,
337 reinterpret_cast<typelib_InterfaceMethodTypeDescription *>(aMemberDescr.get())->pParams,
338 pCallStack, pReturnValue );
339 }
340 break;
341 }
342 default:
343 {
344 throw RuntimeException( "no member description found!", static_cast<XInterface *>(pThis) );
345 }
346 }
347}
348
349extern "C" typedef void (*PrivateSnippetExecutor)();
350
351int const codeSnippetSize = 16;
352
353#if defined (FREEBSD) || defined(NETBSD) || defined(OPENBSD) || defined(MACOSX) || \
354 defined(DRAGONFLY)
355namespace
356{
357 PrivateSnippetExecutor returnsInRegister(typelib_TypeDescriptionReference * pReturnTypeRef)
358 {
359 //These archs apparently are returning small structs in registers, while Linux
360 //doesn't
361 PrivateSnippetExecutor exec=NULL;
362
363 typelib_TypeDescription * pReturnTypeDescr = 0;
364 TYPELIB_DANGER_GET( &pReturnTypeDescr, pReturnTypeRef );
365 const bool bSimpleReturnStruct = x86::isSimpleReturnType(pReturnTypeDescr);
366 const sal_Int32 nRetSize = pReturnTypeDescr->nSize;
367 TYPELIB_DANGER_RELEASE( pReturnTypeDescr );
368 if (bSimpleReturnStruct)
369 {
370 exec = privateSnippetExecutorGeneral; // fills eax
371 if (nRetSize > 4)
372 exec = privateSnippetExecutorHyper; // fills eax/edx
373 }
374 return exec;
375 }
376}
377#endif
378
379unsigned char * codeSnippet(
380 unsigned char * code, sal_PtrDiff writetoexecdiff, sal_Int32 functionIndex, sal_Int32 vtableOffset,
381 typelib_TypeDescriptionReference * pReturnTypeRef)
382{
383 PrivateSnippetExecutor exec;
384 typelib_TypeClass eReturnClass = pReturnTypeRef ? pReturnTypeRef->eTypeClass : typelib_TypeClass_VOID;
385 switch (eReturnClass)
386 {
387 case typelib_TypeClass_VOID:
389 break;
390 case typelib_TypeClass_HYPER:
391 case typelib_TypeClass_UNSIGNED_HYPER:
393 break;
394 case typelib_TypeClass_FLOAT:
396 break;
397 case typelib_TypeClass_DOUBLE:
399 break;
400 case typelib_TypeClass_STRUCT:
401 case typelib_TypeClass_EXCEPTION:
402#if defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) || defined(MACOSX) || \
403 defined(DRAGONFLY)
404 exec = returnsInRegister(pReturnTypeRef);
405 if (!exec)
406 {
408 functionIndex |= 0x80000000;
409 }
410 break;
411#endif
412 case typelib_TypeClass_STRING:
413 case typelib_TypeClass_TYPE:
414 case typelib_TypeClass_ANY:
415 case typelib_TypeClass_SEQUENCE:
416 case typelib_TypeClass_INTERFACE:
418 functionIndex |= 0x80000000;
419 break;
420 default:
422 break;
423 }
424 unsigned char * p = code;
425 assert(sizeof (sal_Int32) == 4);
426 // mov function_index, %eax:
427 *p++ = 0xB8;
428 *reinterpret_cast< sal_Int32 * >(p) = functionIndex;
429 p += sizeof (sal_Int32);
430 // mov vtable_offset, %edx:
431 *p++ = 0xBA;
432 *reinterpret_cast< sal_Int32 * >(p) = vtableOffset;
433 p += sizeof (sal_Int32);
434 // jmp privateSnippetExecutor:
435 *p++ = 0xE9;
436 *reinterpret_cast< sal_Int32 * >(p)
437 = reinterpret_cast<unsigned char *>(exec) - p - sizeof (sal_Int32) - writetoexecdiff;
438 p += sizeof (sal_Int32);
439 assert(p - code <= codeSnippetSize);
440 return code + codeSnippetSize;
441}
442
443}
444
446
449 return static_cast< Slot * >(block) + 2;
450}
451
453 sal_Int32 slotCount)
454{
455 return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize;
456}
457
458namespace {
459// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast
460// on such proxy objects not crash:
461struct ProxyRtti {};
462}
463
466 void * block, sal_Int32 slotCount, sal_Int32,
467 typelib_InterfaceTypeDescription *)
468{
469 Slot * slots = mapBlockToVtable(block);
470 slots[-2].fn = nullptr;
471 slots[-1].fn = &typeid(ProxyRtti);
472 return slots + slotCount;
473}
474
476 Slot ** slots, unsigned char * code, sal_PtrDiff writetoexecdiff,
477 typelib_InterfaceTypeDescription const * type, sal_Int32 functionOffset,
478 sal_Int32 functionCount, sal_Int32 vtableOffset)
479{
480 (*slots) -= functionCount;
481 Slot * s = *slots;
482 for (sal_Int32 i = 0; i < type->nMembers; ++i) {
483 typelib_TypeDescription * member = nullptr;
484 TYPELIB_DANGER_GET(&member, type->ppMembers[i]);
485 assert(member != nullptr);
486 switch (member->eTypeClass) {
487 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
488 // Getter:
489 (s++)->fn = code + writetoexecdiff;
491 code, writetoexecdiff, functionOffset++, vtableOffset,
492 reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >(
493 member)->pAttributeTypeRef);
494 // Setter:
495 if (!reinterpret_cast<
496 typelib_InterfaceAttributeTypeDescription * >(
497 member)->bReadOnly)
498 {
499 (s++)->fn = code + writetoexecdiff;
501 code, writetoexecdiff, functionOffset++, vtableOffset,
502 nullptr);
503 }
504 break;
505
506 case typelib_TypeClass_INTERFACE_METHOD:
507 (s++)->fn = code + writetoexecdiff;
509 code, writetoexecdiff, functionOffset++, vtableOffset,
510 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
511 member)->pReturnTypeRef);
512 break;
513
514 default:
515 assert(false);
516 break;
517 }
518 TYPELIB_DANGER_RELEASE(member);
519 }
520 return code;
521}
522
524 unsigned char const *, unsigned char const *)
525{}
526
527/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
uno_Mapping * getUno2Cpp()
Definition: bridge.hxx:73
uno_ExtEnvironment * getCppEnv()
Definition: bridge.hxx:69
uno_Mapping * getCpp2Uno()
Definition: bridge.hxx:72
A cpp proxy wrapping a uno interface.
static CppInterfaceProxy * castInterfaceToProxy(void *pInterface)
typelib_InterfaceTypeDescription * getTypeDescr()
static Slot * mapBlockToVtable(void *block)
Given a pointer to a block, turn it into a vtable pointer.
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.
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...
static Slot * initializeBlock(void *block, sal_Int32 slotCount, sal_Int32 vtableNumber, typelib_InterfaceTypeDescription *type)
Initialize a raw vtable block.
static std::size_t getBlockSize(sal_Int32 slotCount)
Calculate the size of a raw vtable block.
void SAL_CALL uno_destructData(void *pValue, typelib_TypeDescription *pTypeDescr, uno_ReleaseFunc release) SAL_THROW_EXTERN_C()
void SAL_CALL uno_copyAndConvertData(void *pDest, void *pSource, typelib_TypeDescription *pTypeDescr, uno_Mapping *mapping) SAL_THROW_EXTERN_C()
void cpp_vtable_call(sal_Int32 func, sal_Int32 offset, void **pStack)
is called on incoming vtable calls (called by asm snippets)
void privateSnippetExecutorDouble()
void privateSnippetExecutorClass()
void privateSnippetExecutorFloat()
void privateSnippetExecutorVoid()
void privateSnippetExecutorHyper()
void privateSnippetExecutorGeneral()
const int codeSnippetSize
static unsigned char * codeSnippet(unsigned char *code, sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset, bool bHasHiddenParam)
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)
sal_Int32 nIndex
void * p
sal_uInt16 nPos
#define SAL_WARN(area, stream)
return NULL
struct _typelib_TypeDescription typelib_TypeDescription
Definition: msvc/except.hxx:53
struct _uno_Any uno_Any
Definition: msvc/except.hxx:32
void raiseException(uno_Any *pUnoExc, uno_Mapping *pUno2Cpp)
bool isSimpleType(typelib_TypeClass typeClass)
Determines whether a type is a "simple" type (VOID, BOOLEAN, BYTE, SHORT, UNSIGNED SHORT,...
Definition: types.cxx:28
bool relatesToInterfaceType(typelib_TypeDescription const *type)
Determines whether a type relates to an interface type (is itself an interface type,...
Definition: types.cxx:41
Type
int i
bool isSimpleReturnType(typelib_TypeDescription *pTD, bool recursive=false)
sal_Unicode code
ResultType type