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