nss: upgrade to release 3.73
[LibreOffice.git] / bridges / source / cpp_uno / gcc3_linux_aarch64 / abi.cxx
blobf1cacf8d54babdcfbf419e9e669f05b2a8f45824
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
2 /*
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>
22 #include <cassert>
23 #include <cstddef>
24 #include <cstring>
25 #include <typeinfo>
27 #include <dlfcn.h>
29 #include <com/sun/star/uno/RuntimeException.hpp>
30 #include <com/sun/star/uno/genfunc.h>
31 #include <rtl/strbuf.hxx>
32 #include <rtl/ustrbuf.hxx>
33 #include <rtl/ustring.hxx>
34 #include <sal/log.hxx>
35 #include <sal/types.h>
36 #include <typelib/typeclass.h>
37 #include <typelib/typedescription.h>
38 #include <uno/any2.h>
39 #include <uno/mapping.h>
41 #include "abi.hxx"
42 #include <osl/mutex.hxx>
43 #include <unordered_map>
45 namespace {
47 OUString toUnoName(char const * name) {
48 assert(name != 0);
49 OUStringBuffer b;
50 bool scoped = *name == 'N';
51 if (scoped) {
52 ++name;
54 for (;;) {
55 assert(*name >= '0' && *name <= '9');
56 std::size_t n = *name++ - '0';
57 while (*name >= '0' && *name <= '9') {
58 n = 10 * n + (*name++ - '0');
60 b.appendAscii(name, n);
61 name += n;
62 if (!scoped) {
63 assert(*name == 0);
64 break;
66 if (*name == 'E') {
67 assert(name[1] == 0);
68 break;
70 b.append('.');
72 return b.makeStringAndClear();
75 class Rtti {
76 public:
77 Rtti(): app_(dlopen(0, RTLD_LAZY)) {}
79 ~Rtti() { dlclose(app_); }
81 std::type_info * getRtti(typelib_TypeDescription const & type);
83 private:
84 typedef std::unordered_map<OUString, std::type_info *> Map;
86 void * app_;
88 osl::Mutex mutex_;
89 Map map_;
92 std::type_info * Rtti::getRtti(typelib_TypeDescription const & type) {
93 OUString unoName(type.pTypeName);
94 osl::MutexGuard g(mutex_);
95 Map::iterator i(map_.find(unoName));
96 if (i == map_.end()) {
97 OStringBuffer b;
98 b.append("_ZTIN");
99 for (sal_Int32 j = 0; j != -1;) {
100 OString t(
101 OUStringToOString(
102 unoName.getToken(0, '.', j), RTL_TEXTENCODING_ASCII_US));
103 b.append(t.getLength());
104 b.append(t);
106 b.append('E');
107 OString sym(b.makeStringAndClear());
108 std::type_info * rtti = static_cast<std::type_info *>(
109 dlsym(app_, sym.getStr()));
110 #if defined MACOSX
112 // Horrible but hopefully temporary hack.
114 // For some reason, with the Xcode 12 betas, when compiling for arm64-apple-macos, the
115 // symbols for the typeinfos for the UNO exception types
116 // (_ZTIN3com3sun4star3uno16RuntimeExceptionE etc) end up as "weak private external" in the
117 // object file, as displayed by "nm -f darwin". We try to look them up with dlsym() above,
118 // but that then fails. So use a hackaround... introduce separate real variables (see end of
119 // this file) that point to these typeinfos.
121 // When compiling for x86_64-apple-macos, the typeinfo symbols end up as "weak external"
122 // which is fine.
124 if (rtti == nullptr)
126 const OString ptrSym = "ptr" + sym;
127 auto ptr = static_cast<std::type_info **>(dlsym(app_, ptrSym.getStr()));
128 if (ptr != nullptr)
129 rtti = *ptr;
130 else
131 SAL_WARN("bridges", dlerror());
133 #endif
135 if (rtti == 0) {
136 char const * rttiName = sym.getStr() + std::strlen("_ZTI");
137 assert(type.eTypeClass == typelib_TypeClass_EXCEPTION);
138 typelib_CompoundTypeDescription const & ctd
139 = reinterpret_cast<typelib_CompoundTypeDescription const &>(
140 type);
141 if (ctd.pBaseTypeDescription == 0) {
142 rtti = new __cxxabiv1::__class_type_info(strdup(rttiName));
143 } else {
144 std::type_info * base = getRtti(
145 ctd.pBaseTypeDescription->aBase);
146 rtti = new __cxxabiv1::__si_class_type_info(
147 strdup(rttiName),
148 static_cast<__cxxabiv1::__class_type_info *>(base));
151 i = map_.insert(Map::value_type(unoName, rtti)).first;
153 return i->second;
156 struct theRttiFactory: public rtl::Static<Rtti, theRttiFactory> {};
158 std::type_info * getRtti(typelib_TypeDescription const & type) {
159 return theRttiFactory::get().getRtti(type);
162 extern "C" void _GLIBCXX_CDTOR_CALLABI deleteException(void * exception) {
163 __cxxabiv1::__cxa_exception * header =
164 static_cast<__cxxabiv1::__cxa_exception *>(exception) - 1;
165 #if !defined MACOSX && defined _LIBCPPABI_VERSION // detect libc++abi
166 // First, the libcxxabi commit
167 // <http://llvm.org/viewvc/llvm-project?view=revision&revision=303175>
168 // "[libcxxabi] Align unwindHeader on a double-word boundary" towards
169 // LLVM 5.0 changed the size of __cxa_exception by adding
171 // __attribute__((aligned))
173 // to the final member unwindHeader, on x86-64 effectively adding a hole of
174 // size 8 in front of that member (changing its offset from 88 to 96,
175 // sizeof(__cxa_exception) from 120 to 128, and alignof(__cxa_exception)
176 // from 8 to 16); the "header1" hack below to dynamically determine whether we run against a
177 // LLVM 5 libcxxabi is to look at the exceptionDestructor member, which must
178 // point to this function (the use of __cxa_exception in mapException is
179 // unaffected, as it only accesses members towards the start of the struct,
180 // through a pointer known to actually point at the start). The libcxxabi commit
181 // <https://github.com/llvm/llvm-project/commit/9ef1daa46edb80c47d0486148c0afc4e0d83ddcf>
182 // "Insert padding before the __cxa_exception header to ensure the thrown" in LLVM 6
183 // removes the need for this hack, so the "header1" hack can be removed again once we can be
184 // sure that we only run against libcxxabi from LLVM >= 6.
186 // Second, the libcxxabi commit
187 // <https://github.com/llvm/llvm-project/commit/674ec1eb16678b8addc02a4b0534ab383d22fa77>
188 // "[libcxxabi] Insert padding in __cxa_exception struct for compatibility" in LLVM 10 changed
189 // the layout of the start of __cxa_exception to
191 // [8 byte void *reserve]
192 // 8 byte size_t referenceCount
194 // so the "header2" hack below to dynamically determine whether we run against a LLVM >= 10
195 // libcxxabi is to look whether the exceptionDestructor (with its known value) has increased its
196 // offset by 8. As described in the definition of __cxa_exception
197 // (bridges/source/cpp_uno/gcc3_linux_aarch64/abi.hxx), the "header2" hack (together with the
198 // "#ifdef MACOSX" in the definition of __cxa_exception and the corresponding hack in call in
199 // bridges/source/cpp_uno/gcc3_linux_aarch64/uno2cpp.cxx) can be dropped once we can be sure
200 // that we only run against new libcxxabi that has the reserve member.
201 if (header->exceptionDestructor != &deleteException) {
202 auto const header1 = reinterpret_cast<__cxxabiv1::__cxa_exception *>(
203 reinterpret_cast<char *>(header) - 8);
204 if (header1->exceptionDestructor == &deleteException) {
205 header = header1;
206 } else {
207 auto const header2 = reinterpret_cast<__cxxabiv1::__cxa_exception *>(
208 reinterpret_cast<char *>(header) + 8);
209 if (header2->exceptionDestructor == &deleteException) {
210 header = header2;
211 } else {
212 assert(false);
216 #endif
217 assert(header->exceptionDestructor == &deleteException);
218 OUString unoName(toUnoName(header->exceptionType->name()));
219 typelib_TypeDescription * td = 0;
220 typelib_typedescription_getByName(&td, unoName.pData);
221 assert(td != 0);
222 uno_destructData(exception, td, &css::uno::cpp_release);
223 typelib_typedescription_release(td);
226 enum StructKind {
227 STRUCT_KIND_EMPTY, STRUCT_KIND_FLOAT, STRUCT_KIND_DOUBLE, STRUCT_KIND_POD,
228 STRUCT_KIND_DTOR
231 StructKind getStructKind(typelib_CompoundTypeDescription const * type) {
232 StructKind k = type->pBaseTypeDescription == 0
233 ? STRUCT_KIND_EMPTY : getStructKind(type->pBaseTypeDescription);
234 for (sal_Int32 i = 0; i != type->nMembers; ++i) {
235 StructKind k2 = StructKind();
236 switch (type->ppTypeRefs[i]->eTypeClass) {
237 case typelib_TypeClass_BOOLEAN:
238 case typelib_TypeClass_BYTE:
239 case typelib_TypeClass_SHORT:
240 case typelib_TypeClass_UNSIGNED_SHORT:
241 case typelib_TypeClass_LONG:
242 case typelib_TypeClass_UNSIGNED_LONG:
243 case typelib_TypeClass_HYPER:
244 case typelib_TypeClass_UNSIGNED_HYPER:
245 case typelib_TypeClass_CHAR:
246 case typelib_TypeClass_ENUM:
247 k2 = STRUCT_KIND_POD;
248 break;
249 case typelib_TypeClass_FLOAT:
250 k2 = STRUCT_KIND_FLOAT;
251 break;
252 case typelib_TypeClass_DOUBLE:
253 k2 = STRUCT_KIND_DOUBLE;
254 break;
255 case typelib_TypeClass_STRING:
256 case typelib_TypeClass_TYPE:
257 case typelib_TypeClass_ANY:
258 case typelib_TypeClass_SEQUENCE:
259 case typelib_TypeClass_INTERFACE:
260 k2 = STRUCT_KIND_DTOR;
261 break;
262 case typelib_TypeClass_STRUCT:
264 typelib_TypeDescription * td = 0;
265 TYPELIB_DANGER_GET(&td, type->ppTypeRefs[i]);
266 k2 = getStructKind(
267 reinterpret_cast<typelib_CompoundTypeDescription const *>(
268 td));
269 TYPELIB_DANGER_RELEASE(td);
270 break;
272 default:
273 assert(false);
275 switch (k2) {
276 case STRUCT_KIND_EMPTY:
277 // this means an empty sub-object, which nevertheless obtains a byte
278 // of storage (TODO: does it?), so the full object cannot be a
279 // homogeneous collection of float or double
280 case STRUCT_KIND_POD:
281 assert(k != STRUCT_KIND_DTOR);
282 k = STRUCT_KIND_POD;
283 break;
284 case STRUCT_KIND_FLOAT:
285 case STRUCT_KIND_DOUBLE:
286 if (k == STRUCT_KIND_EMPTY) {
287 k = k2;
288 } else if (k != k2) {
289 assert(k != STRUCT_KIND_DTOR);
290 k = STRUCT_KIND_POD;
292 break;
293 case STRUCT_KIND_DTOR:
294 return STRUCT_KIND_DTOR;
297 return k;
302 namespace abi_aarch64 {
304 void mapException(
305 __cxxabiv1::__cxa_exception * exception, std::type_info const * type, uno_Any * any, uno_Mapping * mapping)
307 assert(exception != 0);
308 assert(type != nullptr);
309 OUString unoName(toUnoName(type->name()));
310 typelib_TypeDescription * td = 0;
311 typelib_typedescription_getByName(&td, unoName.pData);
312 if (td == 0) {
313 css::uno::RuntimeException e("exception type not found: " + unoName);
314 uno_type_any_constructAndConvert(
315 any, &e,
316 cppu::UnoType<css::uno::RuntimeException>::get().getTypeLibType(),
317 mapping);
318 } else {
319 uno_any_constructAndConvert(any, exception->adjustedPtr, td, mapping);
320 typelib_typedescription_release(td);
324 void raiseException(uno_Any * any, uno_Mapping * mapping) {
325 typelib_TypeDescription * td = 0;
326 TYPELIB_DANGER_GET(&td, any->pType);
327 if (td == 0) {
328 throw css::uno::RuntimeException(
329 "no typedescription for " + OUString(any->pType->pTypeName));
331 void * exc = __cxxabiv1::__cxa_allocate_exception(td->nSize);
332 uno_copyAndConvertData(exc, any->pData, td, mapping);
333 uno_any_destruct(any, 0);
334 std::type_info * rtti = getRtti(*td);
335 TYPELIB_DANGER_RELEASE(td);
336 __cxxabiv1::__cxa_throw(exc, rtti, deleteException);
339 ReturnKind getReturnKind(typelib_TypeDescription const * type) {
340 switch (type->eTypeClass) {
341 default:
342 assert(false);
343 #ifdef NDEBUG
344 [[fallthrough]];
345 #endif
346 case typelib_TypeClass_VOID:
347 case typelib_TypeClass_BOOLEAN:
348 case typelib_TypeClass_BYTE:
349 case typelib_TypeClass_SHORT:
350 case typelib_TypeClass_UNSIGNED_SHORT:
351 case typelib_TypeClass_LONG:
352 case typelib_TypeClass_UNSIGNED_LONG:
353 case typelib_TypeClass_HYPER:
354 case typelib_TypeClass_UNSIGNED_HYPER:
355 case typelib_TypeClass_FLOAT:
356 case typelib_TypeClass_DOUBLE:
357 case typelib_TypeClass_CHAR:
358 case typelib_TypeClass_ENUM:
359 assert(type->nSize <= 16);
360 return RETURN_KIND_REG;
361 case typelib_TypeClass_STRING:
362 case typelib_TypeClass_TYPE:
363 case typelib_TypeClass_ANY:
364 case typelib_TypeClass_SEQUENCE:
365 case typelib_TypeClass_INTERFACE:
366 return RETURN_KIND_INDIRECT;
367 case typelib_TypeClass_STRUCT:
368 if (type->nSize > 16) {
369 return RETURN_KIND_INDIRECT;
371 switch (getStructKind(
372 reinterpret_cast<typelib_CompoundTypeDescription const *>(
373 type)))
375 case STRUCT_KIND_FLOAT:
376 return RETURN_KIND_HFA_FLOAT;
377 case STRUCT_KIND_DOUBLE:
378 return RETURN_KIND_HFA_DOUBLE;
379 case STRUCT_KIND_DTOR:
380 return RETURN_KIND_INDIRECT;
381 default:
382 return RETURN_KIND_REG;
389 #ifdef MACOSX
391 // See the comment about the horrible hack above.
393 // This set of types are compiled based on what 'make check' needs, but I haven't been able to run
394 // it completely yet. And of course as such this hack isn't a viable long-term solution.
396 #include <com/sun/star/lang/IllegalArgumentException.hpp>
397 #include <com/sun/star/task/ClassifiedInteractionRequest.hpp>
398 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
399 #include <com/sun/star/ucb/InteractiveIOException.hpp>
400 #include <com/sun/star/ucb/NameClashException.hpp>
401 #include <com/sun/star/uno/Exception.hpp>
403 extern "C" {
404 const std::type_info* __attribute((visibility("default"),used)) ptr_ZTIN3com3sun4star4lang24IllegalArgumentExceptionE = &typeid(css::lang::IllegalArgumentException);
405 const std::type_info* __attribute((visibility("default"),used)) ptr_ZTIN3com3sun4star3uno9ExceptionE = &typeid(css::uno::Exception);
406 const std::type_info* __attribute((visibility("default"),used)) ptr_ZTIN3com3sun4star3uno16RuntimeExceptionE = &typeid(css::uno::RuntimeException);
407 const std::type_info* __attribute((visibility("default"),used)) ptr_ZTIN3com3sun4star3ucb31InteractiveAugmentedIOExceptionE = &typeid(css::ucb::InteractiveAugmentedIOException);
408 const std::type_info* __attribute((visibility("default"),used)) ptr_ZTIN3com3sun4star3ucb22InteractiveIOExceptionE = &typeid(css::ucb::InteractiveIOException);
409 const std::type_info* __attribute((visibility("default"),used)) ptr_ZTIN3com3sun4star3ucb18NameClashExceptionE = &typeid(css::ucb::NameClashException);
410 const std::type_info* __attribute((visibility("default"),used)) ptr_ZTIN3com3sun4star4task28ClassifiedInteractionRequestE = &typeid(css::task::ClassifiedInteractionRequest);
413 #endif
415 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */