LibreOffice Module bridges (master) 1
msvc_win32_x86-64/uno2cpp.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 <sal/config.h>
21
22#include <cassert>
23
24#include <malloc.h>
25
26#include <com/sun/star/uno/genfunc.hxx>
27#include <uno/data.h>
28
29#include <bridge.hxx>
30#include <types.hxx>
31#include <unointerfaceproxy.hxx>
32#include <vtables.hxx>
33
34#include <msvc/except.hxx>
35
36#if OSL_DEBUG_LEVEL > 1
37#include <stdio.h>
38#endif
39
40using namespace ::com::sun::star;
41
42namespace
43{
44
45bool cpp_call(
48 typelib_TypeDescriptionReference * pReturnTypeRef,
49 sal_Int32 nParams,
50 typelib_MethodParameter * pParams,
51 void * pUnoReturn,
52 void * pUnoArgs[],
53 uno_Any ** ppUnoExc ) noexcept
54{
55 const int MAXPARAMS = 32;
56
57 if ( nParams > MAXPARAMS )
58 {
59 // We have a hard limit on the number of parameters so that we
60 // don't need any assembler code here but can call the
61 // function using normal C++.
62
63 return false;
64 }
65
66 // Table with this pointer, optional complex return value ptr, and the parameters
67 union {
68 sal_Int64 i;
69 void *p;
70 double d;
71 } aCppArgs[MAXPARAMS+2], uRetVal;
72 int nCppParamIndex = 0;
73
74 // return type
75 typelib_TypeDescription * pReturnTD = nullptr;
76 TYPELIB_DANGER_GET( &pReturnTD, pReturnTypeRef );
77 assert(pReturnTD);
78
79 // 'this'
80 void * pAdjustedThisPtr = reinterpret_cast<void **>( pThis->getCppI() ) + aVtableSlot.offset;
81 aCppArgs[nCppParamIndex++].p = pAdjustedThisPtr;
82
83 enum class ReturnKind { Void, Simple, Complex, ComplexConvert };
84 ReturnKind retKind;
85 if (pUnoReturn == nullptr) {
86 retKind = ReturnKind::Void;
87 } else {
88 assert(pReturnTD != nullptr);
90 retKind = ReturnKind::Simple;
92 {
93 retKind = ReturnKind::ComplexConvert;
94 aCppArgs[nCppParamIndex++].p = alloca(pReturnTD->nSize);
95 } else {
96 retKind = ReturnKind::Complex;
97 aCppArgs[nCppParamIndex++].p = pUnoReturn;
98 }
99 }
100
101 // indexes of values this have to be converted (interface conversion C++<=>UNO)
102 int pTempCppIndexes[MAXPARAMS];
103 int pTempIndexes[MAXPARAMS];
104 int nTempIndexes = 0;
105
106 // type descriptions for reconversions
107 typelib_TypeDescription *pTempParamTD[MAXPARAMS];
108
109 for (int nPos = 0; nPos < nParams; ++nPos, ++nCppParamIndex)
110 {
111 const typelib_MethodParameter & rParam = pParams[nPos];
112 typelib_TypeDescription * pParamTD = nullptr;
113 TYPELIB_DANGER_GET( &pParamTD, rParam.pTypeRef );
114
115 if (!rParam.bOut && bridges::cpp_uno::shared::isSimpleType(pParamTD))
116 {
117 ::uno_copyAndConvertData(
118 &aCppArgs[nCppParamIndex], pUnoArgs[nPos], pParamTD,
119 pThis->getBridge()->getUno2Cpp() );
120
121 // no longer needed
122 TYPELIB_DANGER_RELEASE( pParamTD );
123 }
124 else // ptr to complex value | ref
125 {
126 if (!rParam.bIn) // Is pure out
127 {
128 // C++ out is constructed mem, UNO out is not!
129 ::uno_constructData(
130 aCppArgs[nCppParamIndex].p = alloca( pParamTD->nSize ),
131 pParamTD );
132
133 pTempCppIndexes[nTempIndexes] = nCppParamIndex;
134
135 // default constructed for C++ call
136 pTempIndexes[nTempIndexes] = nPos;
137
138 // will be released at reconversion
139 pTempParamTD[nTempIndexes++] = pParamTD;
140 }
141 // is in/inout
143 {
144 ::uno_copyAndConvertData(
145 aCppArgs[nCppParamIndex].p = alloca( pParamTD->nSize ),
146 pUnoArgs[nPos], pParamTD,
147 pThis->getBridge()->getUno2Cpp() );
148
149 pTempCppIndexes[nTempIndexes] = nCppParamIndex;
150
151 // has to be reconverted
152 pTempIndexes[nTempIndexes] = nPos;
153
154 // will be released at reconversion
155 pTempParamTD[nTempIndexes++] = pParamTD;
156 }
157 else // direct way
158 {
159 aCppArgs[nCppParamIndex].p = pUnoArgs[nPos];
160 // no longer needed
161 TYPELIB_DANGER_RELEASE( pParamTD );
162 }
163 }
164 }
165
166 __try
167 {
168 // The first real parameter is always 'this'.
169
170 // The Windows x64 calling convention is very regular and
171 // elegant (even if perhaps then slightly slower than the
172 // Linux x64 one): The first four parameters, never more, are
173 // passed in registers, as long as they are a qword in size
174 // or less. (If larger, a pointer to a temp copy is passed, so
175 // it's equivalent anyway.) Floating point values are passed
176 // in XMM0..3 registers, others in RCX, RDX, R8, R9.
177
178 // Now, the nice thing for us is that when calling varargs
179 // functions, floating-point parameters among the four first
180 // ones are always passed *both* in an XMM and integer
181 // register. So we don't need to bother here calling the
182 // method different ways depending on what types of parameters
183 // it actually expects. We just pretend parameters 3..4 are
184 // doubles, and they will be passed both in XMM and integer
185 // registers, and the callee will find them where it
186 // expects. (The callee is not actually varargs, of course.)
187
188 sal_Int64 (*pIMethod)(sal_Int64, ...) =
189 reinterpret_cast<sal_Int64 (*)(sal_Int64, ...)>(
190 (*static_cast<sal_uInt64 **>(pAdjustedThisPtr))[aVtableSlot.index]);
191
192 double (*pFMethod)(sal_Int64, ...) =
193 reinterpret_cast<double (*)(sal_Int64, ...)>(
194 (*static_cast<sal_uInt64 **>(pAdjustedThisPtr))[aVtableSlot.index]);
195
196 // Pass parameters 2..4 as if it was a floating-point value so
197 // that it gets put in both XMM and integer registers per the
198 // calling convention. It doesn't matter if it actually is a
199 // fp or not.
200
201 if ( pReturnTD &&
202 (pReturnTD->eTypeClass == typelib_TypeClass_FLOAT ||
203 pReturnTD->eTypeClass == typelib_TypeClass_DOUBLE) )
204 uRetVal.d =
205 pFMethod (aCppArgs[0].i, aCppArgs[1].d, aCppArgs[2].d, aCppArgs[3].d,
206 aCppArgs[4].i, aCppArgs[5].i, aCppArgs[6].i, aCppArgs[7].i,
207 aCppArgs[8].i, aCppArgs[9].i, aCppArgs[10].i, aCppArgs[11].i,
208 aCppArgs[12].i, aCppArgs[13].i, aCppArgs[14].i, aCppArgs[15].i,
209 aCppArgs[16].i, aCppArgs[17].i, aCppArgs[18].i, aCppArgs[19].i,
210 aCppArgs[20].i, aCppArgs[21].i, aCppArgs[22].i, aCppArgs[23].i,
211 aCppArgs[24].i, aCppArgs[25].i, aCppArgs[26].i, aCppArgs[27].i,
212 aCppArgs[28].i, aCppArgs[29].i, aCppArgs[30].i, aCppArgs[31].i );
213 else
214 uRetVal.i =
215 pIMethod (aCppArgs[0].i, aCppArgs[1].d, aCppArgs[2].d, aCppArgs[3].d,
216 aCppArgs[4].i, aCppArgs[5].i, aCppArgs[6].i, aCppArgs[7].i,
217 aCppArgs[8].i, aCppArgs[9].i, aCppArgs[10].i, aCppArgs[11].i,
218 aCppArgs[12].i, aCppArgs[13].i, aCppArgs[14].i, aCppArgs[15].i,
219 aCppArgs[16].i, aCppArgs[17].i, aCppArgs[18].i, aCppArgs[19].i,
220 aCppArgs[20].i, aCppArgs[21].i, aCppArgs[22].i, aCppArgs[23].i,
221 aCppArgs[24].i, aCppArgs[25].i, aCppArgs[26].i, aCppArgs[27].i,
222 aCppArgs[28].i, aCppArgs[29].i, aCppArgs[30].i, aCppArgs[31].i );
223 }
224 __except (msvc_filterCppException(
225 GetExceptionInformation(),
226 *ppUnoExc, pThis->getBridge()->getCpp2Uno() ))
227 {
228 // *ppUnoExc was constructed by filter function
229 // temporary params
230 while (nTempIndexes--)
231 {
232 int nCppIndex = pTempCppIndexes[nTempIndexes];
233 // destroy temp C++ param => C++: every param was constructed
234 ::uno_destructData(
235 aCppArgs[nCppIndex].p, pTempParamTD[nTempIndexes],
236 uno::cpp_release );
237 TYPELIB_DANGER_RELEASE( pTempParamTD[nTempIndexes] );
238 }
239
240 // return type
241 if (pReturnTD)
242 TYPELIB_DANGER_RELEASE( pReturnTD );
243
244 return true;
245 }
246
247 // NO exception occurred
248 *ppUnoExc = nullptr;
249
250 // reconvert temporary params
251 while (nTempIndexes--)
252 {
253 int nCppIndex = pTempCppIndexes[nTempIndexes];
254 int nIndex = pTempIndexes[nTempIndexes];
255 typelib_TypeDescription * pParamTD =
256 pTempParamTD[nTempIndexes];
257
258 if (pParams[nIndex].bIn)
259 {
260 if (pParams[nIndex].bOut) // inout
261 {
262 ::uno_destructData(
263 pUnoArgs[nIndex], pParamTD, nullptr ); // destroy UNO value
264 ::uno_copyAndConvertData(
265 pUnoArgs[nIndex], aCppArgs[nCppIndex].p, pParamTD,
266 pThis->getBridge()->getCpp2Uno() );
267 }
268 }
269 else // pure out
270 {
271 ::uno_copyAndConvertData(
272 pUnoArgs[nIndex], aCppArgs[nCppIndex].p, pParamTD,
273 pThis->getBridge()->getCpp2Uno() );
274 }
275
276 // destroy temp C++ param => C++: every param was constructed
277 ::uno_destructData(
278 aCppArgs[nCppIndex].p, pParamTD, uno::cpp_release );
279
280 TYPELIB_DANGER_RELEASE( pParamTD );
281 }
282
283 // return value
284 switch (retKind) {
285 case ReturnKind::Void:
286 break;
287 case ReturnKind::Simple:
288 *static_cast<sal_Int64*>(pUnoReturn) = uRetVal.i;
289 break;
290 case ReturnKind::Complex:
291 assert(uRetVal.p == pUnoReturn);
292 break;
293 case ReturnKind::ComplexConvert:
294 assert(uRetVal.p == aCppArgs[1].p);
295 ::uno_copyAndConvertData(
296 pUnoReturn, uRetVal.p, pReturnTD,
297 pThis->getBridge()->getCpp2Uno() );
298 ::uno_destructData(
299 uRetVal.p, pReturnTD, uno::cpp_release );
300 break;
301 }
302
303 // return type
304 if ( pReturnTD )
305 TYPELIB_DANGER_RELEASE( pReturnTD );
306
307 return true;
308}
309
310} // namespace
311
312namespace bridges::cpp_uno::shared {
313
315 uno_Interface * pUnoI,
316 const typelib_TypeDescription * pMemberTD,
317 void * pReturn,
318 void * pArgs[],
319 uno_Any ** ppException )
320{
321 // is my surrogate
323 = static_cast< bridges::cpp_uno::shared::UnoInterfaceProxy * >(pUnoI);
324#if OSL_DEBUG_LEVEL > 0
325 typelib_InterfaceTypeDescription * pTypeDescr = pThis->pTypeDescr;
326#endif
327
328 switch (pMemberTD->eTypeClass)
329 {
330 case typelib_TypeClass_INTERFACE_ATTRIBUTE:
331 {
332#if OSL_DEBUG_LEVEL > 0
333 // determine vtable call index
334 sal_Int32 nMemberPos = reinterpret_cast<typelib_InterfaceMemberTypeDescription const *>(pMemberTD)->nPosition;
335 assert(nMemberPos < pTypeDescr->nAllMembers);
336#endif
337 VtableSlot aVtableSlot(
339 reinterpret_cast<
340 typelib_InterfaceAttributeTypeDescription const * >(
341 pMemberTD)));
342 if ( pReturn )
343 {
344 // is GET
345 cpp_call(
346 pThis, aVtableSlot,
347 reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>(pMemberTD)->pAttributeTypeRef,
348 0, nullptr, // no params
349 pReturn, pArgs, ppException );
350 }
351 else
352 {
353 // is SET
354 typelib_MethodParameter aParam;
355 aParam.pTypeRef =
356 reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>(pMemberTD)->pAttributeTypeRef;
357 aParam.bIn = true;
358 aParam.bOut = false;
359
360 typelib_TypeDescriptionReference * pReturnTypeRef = nullptr;
361 OUString aVoidName("void");
363 &pReturnTypeRef, typelib_TypeClass_VOID, aVoidName.pData );
364
365 aVtableSlot.index += 1; // get, then set method
366 cpp_call(
367 pThis, aVtableSlot,
368 pReturnTypeRef,
369 1, &aParam,
370 pReturn, pArgs, ppException );
371
373 }
374
375 break;
376 }
377 case typelib_TypeClass_INTERFACE_METHOD:
378 {
379#if OSL_DEBUG_LEVEL > 0
380 // determine vtable call index
381 sal_Int32 nMemberPos = reinterpret_cast<typelib_InterfaceMemberTypeDescription const *>(pMemberTD)->nPosition;
382 assert(nMemberPos < pTypeDescr->nAllMembers);
383#endif
384 VtableSlot aVtableSlot(
386 reinterpret_cast<
387 typelib_InterfaceMethodTypeDescription const * >(
388 pMemberTD)));
389
390 switch (aVtableSlot.index)
391 {
392 case 1: // acquire UNO interface
393 (*pUnoI->acquire)( pUnoI );
394 *ppException = nullptr;
395 break;
396 case 2: // release UNO interface
397 (*pUnoI->release)( pUnoI );
398 *ppException = nullptr;
399 break;
400 case 0: // queryInterface() opt
401 {
402 typelib_TypeDescription * pTD = nullptr;
403 TYPELIB_DANGER_GET( &pTD, static_cast< uno::Type * >( pArgs[0] )->getTypeLibType() );
404
405 if ( pTD )
406 {
407 uno_Interface * pInterface = nullptr;
408 (*pThis->getBridge()->getUnoEnv()->getRegisteredInterface)(
409 pThis->getBridge()->getUnoEnv(),
410 reinterpret_cast<void **>(&pInterface), pThis->oid.pData, reinterpret_cast<typelib_InterfaceTypeDescription *>(pTD) );
411
412 if ( pInterface )
413 {
414 ::uno_any_construct(
415 static_cast< uno_Any * >( pReturn ),
416 &pInterface, pTD, nullptr );
417 (*pInterface->release)( pInterface );
418 TYPELIB_DANGER_RELEASE( pTD );
419 *ppException = nullptr;
420 break;
421 }
422 TYPELIB_DANGER_RELEASE( pTD );
423 }
424 [[fallthrough]]; // else perform queryInterface()
425 }
426 default:
427 typelib_InterfaceMethodTypeDescription const* pMethodTD
428 = reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberTD);
429
430 if (!cpp_call(pThis, aVtableSlot, pMethodTD->pReturnTypeRef, pMethodTD->nParams,
431 pMethodTD->pParams, pReturn, pArgs, ppException))
432 {
433 uno::RuntimeException aExc( "Too many parameters!" );
434
435 uno::Type const & rExcType = cppu::UnoType<decltype(aExc)>::get();
436 ::uno_type_any_construct(*ppException, &aExc, rExcType.getTypeLibType(), nullptr);
437 }
438 }
439 break;
440 }
441 default:
442 {
443 uno::RuntimeException aExc("Illegal member type description!", uno::Reference<uno::XInterface>());
444
445 uno::Type const & rExcType = cppu::UnoType<decltype(aExc)>::get();
446 // binary identical null reference
447 ::uno_type_any_construct(*ppException, &aExc, rExcType.getTypeLibType(), nullptr);
448 }
449 }
450}
451
452}
453
454/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
uno_ExtEnvironment * getUnoEnv()
Definition: bridge.hxx:70
A uno proxy wrapping a cpp interface.
typelib_InterfaceTypeDescription * pTypeDescr
static void cpp_call(bridges::cpp_uno::shared::UnoInterfaceProxy *pThis, bridges::cpp_uno::shared::VtableSlot aVtableSlot, typelib_TypeDescriptionReference *pReturnTypeRef, sal_Int32 nParams, typelib_MethodParameter *pParams, void *pUnoReturn, void *pUnoArgs[], uno_Any **ppUnoExc)
sal_Int32 nIndex
void * p
double d
sal_uInt16 nPos
struct _typelib_TypeDescription typelib_TypeDescription
Definition: msvc/except.hxx:52
struct _uno_Any uno_Any
Definition: msvc/except.hxx:31
int msvc_filterCppException(EXCEPTION_POINTERS *pPointers, uno_Any *pUnoExc, uno_Mapping *pCpp2Uno)
void unoInterfaceProxyDispatch(uno_Interface *pUnoI, const typelib_TypeDescription *pMemberDescr, void *pReturn, void *pArgs[], uno_Any **ppException)
VtableSlot getVtableSlot(typelib_InterfaceAttributeTypeDescription const *ifcMember)
Calculates the vtable slot associated with an interface attribute member.
Definition: vtables.cxx:132
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
int i
Represents a vtable slot of a C++ class.
Definition: vtables.hxx:60
void SAL_CALL typelib_typedescriptionreference_new(typelib_TypeDescriptionReference **ppTDR, typelib_TypeClass eTypeClass, rtl_uString *pTypeName) SAL_THROW_EXTERN_C()
void SAL_CALL typelib_typedescriptionreference_release(typelib_TypeDescriptionReference *pRef) SAL_THROW_EXTERN_C()