1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
29 #include <unointerfaceproxy.hxx>
30 #include <vtables.hxx>
31 #include <com/sun/star/uno/Exception.hpp>
32 #include <com/sun/star/uno/RuntimeException.hpp>
33 #include <com/sun/star/uno/genfunc.hxx>
34 #include <rtl/textenc.h>
35 #include <rtl/ustring.hxx>
36 #include <sal/alloca.h>
37 #include <sal/types.h>
38 #include <typelib/typeclass.h>
39 #include <typelib/typedescription.h>
44 #include "callvirtualfunction.hxx"
50 typelib_TypeClass typeclass
,
51 sal_Int32
* const subsp
,
53 unsigned long value
, unsigned long * const stack
, sal_Int32
* const sp
,
54 unsigned long * const regs
, sal_Int32
* const nregs
)
59 regs
[(*nregs
)++] = value
;
64 case typelib_TypeClass_BOOLEAN
:
65 case typelib_TypeClass_BYTE
:
66 *reinterpret_cast<uint8_t*>(reinterpret_cast<uintptr_t>(stack
+ *sp
) + *subsp
) = value
;
74 case typelib_TypeClass_SHORT
:
75 case typelib_TypeClass_UNSIGNED_SHORT
:
76 case typelib_TypeClass_CHAR
:
77 *subsp
= (*subsp
+ 1) & ~0x1;
83 *reinterpret_cast<uint16_t*>(reinterpret_cast<uintptr_t>(stack
+ *sp
) + *subsp
) = value
;
91 case typelib_TypeClass_LONG
:
92 case typelib_TypeClass_UNSIGNED_LONG
:
93 case typelib_TypeClass_ENUM
:
94 case typelib_TypeClass_FLOAT
:
95 *subsp
= (*subsp
+ 3) & ~0x3;
101 *reinterpret_cast<uint32_t*>(reinterpret_cast<uintptr_t>(stack
+ *sp
) + *subsp
) = value
;
109 case typelib_TypeClass_HYPER
:
110 case typelib_TypeClass_UNSIGNED_HYPER
:
123 (*nregs
!= 8 ? regs
[(*nregs
)++] : stack
[(*sp
)++]) = value
;
128 bridges::cpp_uno::shared::UnoInterfaceProxy
* proxy
,
129 bridges::cpp_uno::shared::VtableSlot slot
,
130 typelib_TypeDescriptionReference
* returnType
, sal_Int32 count
,
131 typelib_MethodParameter
* parameters
, void * returnValue
, void ** arguments
,
132 uno_Any
** exception
)
134 typelib_TypeDescription
* rtd
= nullptr;
135 TYPELIB_DANGER_GET(&rtd
, returnType
);
136 abi_aarch64::ReturnKind retKind
= abi_aarch64::getReturnKind(rtd
);
137 bool retConv
= bridges::cpp_uno::shared::relatesToInterfaceType(rtd
);
138 void * ret
= retConv
? alloca(rtd
->nSize
) : returnValue
;
139 unsigned long ** thisPtr
140 = reinterpret_cast<unsigned long **>(proxy
->getCppI()) + slot
.offset
;
141 unsigned long * stack
= static_cast<unsigned long *>(
142 alloca(count
* sizeof (unsigned long)));
147 unsigned long gpr
[8];
149 unsigned long fpr
[8];
151 gpr
[ngpr
++] = reinterpret_cast<unsigned long>(thisPtr
);
152 void ** cppArgs
= static_cast<void **>(alloca(count
* sizeof (void *)));
153 typelib_TypeDescription
** ptds
=
154 static_cast<typelib_TypeDescription
**>(
155 alloca(count
* sizeof (typelib_TypeDescription
*)));
156 for (sal_Int32 i
= 0; i
!= count
; ++i
) {
157 if (!parameters
[i
].bOut
&&
158 bridges::cpp_uno::shared::isSimpleType(parameters
[i
].pTypeRef
))
160 cppArgs
[i
] = nullptr;
161 switch (parameters
[i
].pTypeRef
->eTypeClass
) {
162 case typelib_TypeClass_BOOLEAN
:
165 parameters
[i
].pTypeRef
->eTypeClass
, &subsp
,
167 static_cast<unsigned long>(*static_cast<sal_Bool
*>(arguments
[i
])), stack
, &sp
,
170 case typelib_TypeClass_BYTE
:
173 parameters
[i
].pTypeRef
->eTypeClass
, &subsp
,
175 *static_cast<sal_Int8
*>(arguments
[i
]), stack
, &sp
, gpr
,
178 case typelib_TypeClass_SHORT
:
181 parameters
[i
].pTypeRef
->eTypeClass
, &subsp
,
183 *static_cast<sal_Int16
*>(arguments
[i
]), stack
, &sp
, gpr
,
186 case typelib_TypeClass_UNSIGNED_SHORT
:
189 parameters
[i
].pTypeRef
->eTypeClass
, &subsp
,
191 *static_cast<sal_uInt16
*>(arguments
[i
]), stack
, &sp
, gpr
,
194 case typelib_TypeClass_LONG
:
195 case typelib_TypeClass_ENUM
:
198 parameters
[i
].pTypeRef
->eTypeClass
, &subsp
,
200 *static_cast<sal_Int32
*>(arguments
[i
]), stack
, &sp
, gpr
,
203 case typelib_TypeClass_UNSIGNED_LONG
:
206 parameters
[i
].pTypeRef
->eTypeClass
, &subsp
,
208 *static_cast<sal_uInt32
*>(arguments
[i
]), stack
, &sp
, gpr
,
211 case typelib_TypeClass_HYPER
:
214 parameters
[i
].pTypeRef
->eTypeClass
, &subsp
,
216 *static_cast<sal_Int64
*>(arguments
[i
]), stack
, &sp
, gpr
,
219 case typelib_TypeClass_UNSIGNED_HYPER
:
222 parameters
[i
].pTypeRef
->eTypeClass
, &subsp
,
224 *static_cast<sal_uInt64
*>(arguments
[i
]), stack
, &sp
, gpr
,
227 case typelib_TypeClass_FLOAT
:
230 parameters
[i
].pTypeRef
->eTypeClass
, &subsp
,
232 *static_cast<unsigned int *>(arguments
[i
]), stack
, &sp
, fpr
,
235 case typelib_TypeClass_DOUBLE
:
238 parameters
[i
].pTypeRef
->eTypeClass
, &subsp
,
240 *static_cast<unsigned long *>(arguments
[i
]), stack
, &sp
,
243 case typelib_TypeClass_CHAR
:
246 parameters
[i
].pTypeRef
->eTypeClass
, &subsp
,
248 *static_cast<sal_Unicode
*>(arguments
[i
]), stack
, &sp
, gpr
,
255 typelib_TypeDescription
* ptd
= nullptr;
256 TYPELIB_DANGER_GET(&ptd
, parameters
[i
].pTypeRef
);
257 if (!parameters
[i
].bIn
) {
258 cppArgs
[i
] = alloca(ptd
->nSize
);
259 uno_constructData(cppArgs
[i
], ptd
);
263 typelib_TypeClass_HYPER
, &subsp
,
265 reinterpret_cast<unsigned long>(cppArgs
[i
]), stack
, &sp
,
267 } else if (bridges::cpp_uno::shared::relatesToInterfaceType(ptd
)) {
268 cppArgs
[i
] = alloca(ptd
->nSize
);
269 uno_copyAndConvertData(
270 cppArgs
[i
], arguments
[i
], ptd
,
271 proxy
->getBridge()->getUno2Cpp());
275 typelib_TypeClass_HYPER
, &subsp
,
277 reinterpret_cast<unsigned long>(cppArgs
[i
]), stack
, &sp
,
280 cppArgs
[i
] = nullptr;
283 typelib_TypeClass_HYPER
, &subsp
,
285 reinterpret_cast<unsigned long>(arguments
[i
]), stack
, &sp
,
287 TYPELIB_DANGER_RELEASE(ptd
);
294 (*thisPtr
)[slot
.index
], gpr
, fpr
, stack
, sp
, ret
);
295 } catch (css::uno::Exception
&) {
297 } catch (std::exception
& e
) {
298 throw css::uno::RuntimeException(
300 + OStringToOUString(typeid(e
).name(), RTL_TEXTENCODING_UTF8
)
301 + ": " + OStringToOUString(e
.what(), RTL_TEXTENCODING_UTF8
));
303 throw css::uno::RuntimeException(
304 "C++ code threw unknown exception");
306 } catch (css::uno::Exception
&) {
307 __cxxabiv1::__cxa_exception
* header
= reinterpret_cast<__cxxabiv1::__cxa_eh_globals
*>(
308 __cxxabiv1::__cxa_get_globals())->caughtExceptions
;
309 #if !defined MACOSX && defined _LIBCPPABI_VERSION // detect libc++abi
310 // Very bad HACK to find out whether we run against a libcxxabi that has a new
311 // __cxa_exception::reserved member at the start, introduced with LLVM 10
312 // <https://github.com/llvm/llvm-project/commit/674ec1eb16678b8addc02a4b0534ab383d22fa77>
313 // "[libcxxabi] Insert padding in __cxa_exception struct for compatibility". The layout of
314 // the start of __cxa_exception is
316 // [8 byte void *reserve]
317 // 8 byte size_t referenceCount
319 // where the (bad, hacky) assumption is that reserve (if present) is null
320 // (__cxa_allocate_exception in at least LLVM 11 zero-fills the object, and nothing actively
321 // sets reserve) while referenceCount is non-null (__cxa_throw sets it to 1, and
322 // __cxa_decrement_exception_refcount destroys the exception as soon as it drops to 0; for a
323 // __cxa_dependent_exception, the referenceCount member is rather
325 // 8 byte void* primaryException
327 // but which also will always be set to a non-null value in
328 // __cxa_rethrow_primary_exception). As described in the definition of __cxa_exception
329 // (bridges/source/cpp_uno/gcc3_linux_aarch64/abi.hxx), this hack (together with the
330 // "#ifdef MACOSX" there) can be dropped once we can be sure that we only run against new
331 // libcxxabi that has the reserve member:
332 if (*reinterpret_cast<void **>(header
) == nullptr) {
333 header
= reinterpret_cast<__cxxabiv1::__cxa_exception
*>(
334 reinterpret_cast<void **>(header
) + 1);
337 abi_aarch64::mapException(
339 __cxxabiv1::__cxa_current_exception_type(), *exception
,
340 proxy
->getBridge()->getCpp2Uno());
341 for (sal_Int32 i
= 0; i
!= count
; ++i
) {
342 if (cppArgs
[i
] != nullptr) {
345 reinterpret_cast<uno_ReleaseFunc
>(css::uno::cpp_release
));
346 TYPELIB_DANGER_RELEASE(ptds
[i
]);
349 TYPELIB_DANGER_RELEASE(rtd
);
352 *exception
= nullptr;
353 for (sal_Int32 i
= 0; i
!= count
; ++i
) {
354 if (cppArgs
[i
] != nullptr) {
355 if (parameters
[i
].bOut
) {
356 if (parameters
[i
].bIn
) {
357 uno_destructData(arguments
[i
], ptds
[i
], nullptr);
359 uno_copyAndConvertData(
360 arguments
[i
], cppArgs
[i
], ptds
[i
],
361 proxy
->getBridge()->getCpp2Uno());
365 reinterpret_cast<uno_ReleaseFunc
>(css::uno::cpp_release
));
366 TYPELIB_DANGER_RELEASE(ptds
[i
]);
370 case abi_aarch64::RETURN_KIND_REG
:
371 switch (rtd
->eTypeClass
) {
372 case typelib_TypeClass_VOID
:
374 case typelib_TypeClass_BOOLEAN
:
375 case typelib_TypeClass_BYTE
:
376 case typelib_TypeClass_SHORT
:
377 case typelib_TypeClass_UNSIGNED_SHORT
:
378 case typelib_TypeClass_LONG
:
379 case typelib_TypeClass_UNSIGNED_LONG
:
380 case typelib_TypeClass_HYPER
:
381 case typelib_TypeClass_UNSIGNED_HYPER
:
382 case typelib_TypeClass_CHAR
:
383 case typelib_TypeClass_ENUM
:
384 case typelib_TypeClass_STRUCT
:
385 std::memcpy(ret
, gpr
, rtd
->nSize
);
387 case typelib_TypeClass_FLOAT
:
388 case typelib_TypeClass_DOUBLE
:
389 std::memcpy(ret
, fpr
, rtd
->nSize
);
395 case abi_aarch64::RETURN_KIND_HFA_FLOAT
:
396 switch (rtd
->nSize
) {
398 std::memcpy(static_cast<char *>(ret
) + 12, fpr
+ 3, 4);
401 std::memcpy(static_cast<char *>(ret
) + 8, fpr
+ 2, 4);
404 std::memcpy(static_cast<char *>(ret
) + 4, fpr
+ 1, 4);
407 std::memcpy(ret
, fpr
, 4);
413 case abi_aarch64::RETURN_KIND_HFA_DOUBLE
:
414 std::memcpy(ret
, fpr
, rtd
->nSize
);
416 case abi_aarch64::RETURN_KIND_INDIRECT
:
420 uno_copyAndConvertData(
421 returnValue
, ret
, rtd
, proxy
->getBridge()->getCpp2Uno());
423 ret
, rtd
, reinterpret_cast<uno_ReleaseFunc
>(css::uno::cpp_release
));
425 TYPELIB_DANGER_RELEASE(rtd
);
430 namespace bridges::cpp_uno::shared
{
432 void unoInterfaceProxyDispatch(
433 uno_Interface
* pUnoI
, typelib_TypeDescription
const * pMemberDescr
,
434 void * pReturn
, void ** pArgs
, uno_Any
** ppException
)
436 UnoInterfaceProxy
* proxy
= static_cast<UnoInterfaceProxy
*>(pUnoI
);
437 switch (pMemberDescr
->eTypeClass
) {
438 case typelib_TypeClass_INTERFACE_ATTRIBUTE
:
440 typelib_InterfaceAttributeTypeDescription
const * atd
442 typelib_InterfaceAttributeTypeDescription
const *>(
444 VtableSlot
slot(getVtableSlot(atd
));
445 if (pReturn
!= nullptr) { // getter
447 proxy
, slot
, atd
->pAttributeTypeRef
, 0, nullptr, pReturn
, pArgs
,
450 typelib_MethodParameter param
= {
451 nullptr, atd
->pAttributeTypeRef
, true, false };
452 typelib_TypeDescriptionReference
* rtd
= nullptr;
453 typelib_typedescriptionreference_new(
454 &rtd
, typelib_TypeClass_VOID
, OUString("void").pData
);
456 call(proxy
, slot
, rtd
, 1, ¶m
, pReturn
, pArgs
, ppException
);
457 typelib_typedescriptionreference_release(rtd
);
461 case typelib_TypeClass_INTERFACE_METHOD
:
463 typelib_InterfaceMethodTypeDescription
const * mtd
465 typelib_InterfaceMethodTypeDescription
const *>(
467 VtableSlot
slot(getVtableSlot(mtd
));
468 switch (slot
.index
) {
470 pUnoI
->acquire(pUnoI
);
471 *ppException
= nullptr;
474 pUnoI
->release(pUnoI
);
475 *ppException
= nullptr;
479 typelib_TypeDescription
* td
= nullptr;
482 (static_cast<css::uno::Type
*>(pArgs
[0])
483 ->getTypeLibType()));
485 uno_Interface
* ifc
= nullptr;
486 proxy
->pBridge
->getUnoEnv()->getRegisteredInterface(
487 proxy
->pBridge
->getUnoEnv(),
488 reinterpret_cast<void **>(&ifc
), proxy
->oid
.pData
,
490 typelib_InterfaceTypeDescription
*>(td
));
491 if (ifc
!= nullptr) {
493 static_cast<uno_Any
*>(pReturn
), &ifc
, td
,
496 TYPELIB_DANGER_RELEASE(td
);
497 *ppException
= nullptr;
500 TYPELIB_DANGER_RELEASE(td
);
506 proxy
, slot
, mtd
->pReturnTypeRef
, mtd
->nParams
,
507 mtd
->pParams
, pReturn
, pArgs
, ppException
);
519 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */