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>
25 #include <unordered_map>
31 #include <osl/mutex.hxx>
32 #include <rtl/instance.hxx>
33 #include <rtl/strbuf.hxx>
34 #include <rtl/ustring.hxx>
35 #include <sal/log.hxx>
36 #include <typelib/typedescription.h>
45 virtual ~Generated() {};
47 virtual std::type_info
* get() const = 0;
50 class GeneratedPlain
: public Generated
{
52 GeneratedPlain(std::unique_ptr
<std::type_info
> && info
): info_(std::move(info
)) {};
54 std::type_info
* get() const override
{ return info_
.get(); }
57 std::unique_ptr
<std::type_info
> info_
;
60 class GeneratedPad
: public Generated
{
63 GeneratedPad(std::unique_ptr
<char[]> && pad
): pad_(std::move(pad
)) {};
65 ~GeneratedPad() override
{ get()->~type_info(); }
67 std::type_info
* get() const override
68 { return reinterpret_cast<std::type_info
*>(pad_
.get()); }
71 std::unique_ptr
<char[]> pad_
;
76 typedef std::unordered_map
< OUString
, std::type_info
* > t_rtti_map
;
80 std::vector
<OString
> m_rttiNames
;
81 std::unordered_map
<OUString
, std::unique_ptr
<Generated
>> m_generatedRttis
;
89 std::type_info
* getRTTI(typelib_TypeDescription
const &);
93 : m_hApp( dlopen( nullptr, RTLD_LAZY
) )
102 std::type_info
* RTTI::getRTTI(typelib_TypeDescription
const & pTypeDescr
)
104 std::type_info
* rtti
;
106 OUString
const & unoName
= OUString::unacquired(&pTypeDescr
.pTypeName
);
108 osl::MutexGuard
guard( m_mutex
);
109 t_rtti_map::const_iterator
iFind( m_rttis
.find( unoName
) );
110 if (iFind
== m_rttis
.end())
113 OStringBuffer
buf( 64 );
114 buf
.append( "_ZTIN" );
118 OUString
token( unoName
.getToken( 0, '.', index
) );
119 buf
.append( token
.getLength() );
120 OString
c_token( OUStringToOString( token
, RTL_TEXTENCODING_ASCII_US
) );
121 buf
.append( c_token
);
126 OString
symName( buf
.makeStringAndClear() );
127 rtti
= static_cast<std::type_info
*>(dlsym( m_hApp
, symName
.getStr() ));
131 std::pair
< t_rtti_map::iterator
, bool > insertion (
132 m_rttis
.insert( t_rtti_map::value_type( unoName
, rtti
) ) );
133 SAL_WARN_IF( !insertion
.second
, "bridges", "key " << unoName
<< " already in rtti map" );
137 // try to lookup the symbol in the generated rtti map
138 auto iFind2( m_generatedRttis
.find( unoName
) );
139 if (iFind2
== m_generatedRttis
.end())
141 // we must generate it !
142 // symbol and rtti-name is nearly identical,
143 // the symbol is prefixed with _ZTI
144 char const * rttiName
= symName
.getStr() +4;
145 #if OSL_DEBUG_LEVEL > 1
146 fprintf( stderr
,"generated rtti for %s\n", rttiName
);
148 std::unique_ptr
<Generated
> newRtti
;
149 switch (pTypeDescr
.eTypeClass
) {
150 case typelib_TypeClass_EXCEPTION
:
152 typelib_CompoundTypeDescription
const & ctd
154 typelib_CompoundTypeDescription
const &>(
156 if (ctd
.pBaseTypeDescription
)
158 // ensure availability of base
159 std::type_info
* base_rtti
= getRTTI(
160 ctd
.pBaseTypeDescription
->aBase
);
161 m_rttiNames
.emplace_back(OString(rttiName
));
162 std::unique_ptr
<std::type_info
> info(
163 new __cxxabiv1::__si_class_type_info(
164 m_rttiNames
.back().getStr(), static_cast<__cxxabiv1::__class_type_info
*>(base_rtti
) ));
165 newRtti
.reset(new GeneratedPlain(std::move(info
)));
169 // this class has no base class
170 m_rttiNames
.emplace_back(OString(rttiName
));
171 std::unique_ptr
<std::type_info
> info(
172 new __cxxabiv1::__class_type_info(m_rttiNames
.back().getStr()));
173 newRtti
.reset(new GeneratedPlain(std::move(info
)));
177 case typelib_TypeClass_INTERFACE
:
179 typelib_InterfaceTypeDescription
const & itd
181 typelib_InterfaceTypeDescription
const &>(
183 std::vector
<std::type_info
*> bases
;
184 for (sal_Int32 i
= 0; i
!= itd
.nBaseTypes
; ++i
) {
185 bases
.push_back(getRTTI(itd
.ppBaseTypes
[i
]->aBase
));
187 switch (itd
.nBaseTypes
) {
190 m_rttiNames
.emplace_back(OString(rttiName
));
191 std::unique_ptr
<std::type_info
> info(
192 new __cxxabiv1::__class_type_info(
193 m_rttiNames
.back().getStr()));
194 newRtti
.reset(new GeneratedPlain(std::move(info
)));
199 m_rttiNames
.emplace_back(OString(rttiName
));
200 std::unique_ptr
<std::type_info
> info(
201 new __cxxabiv1::__si_class_type_info(
202 m_rttiNames
.back().getStr(),
204 __cxxabiv1::__class_type_info
*>(
206 newRtti
.reset(new GeneratedPlain(std::move(info
)));
211 m_rttiNames
.emplace_back(OString(rttiName
));
212 auto pad
= std::make_unique
<char[]>(
213 sizeof (__cxxabiv1::__vmi_class_type_info
)
214 + ((itd
.nBaseTypes
- 1)
216 __cxxabiv1::__base_class_type_info
)));
217 __cxxabiv1::__vmi_class_type_info
* info
219 __cxxabiv1::__vmi_class_type_info(
220 m_rttiNames
.back().getStr(),
221 __cxxabiv1::__vmi_class_type_info::__flags_unknown_mask
);
222 info
->__base_count
= itd
.nBaseTypes
;
223 for (sal_Int32 i
= 0; i
!= itd
.nBaseTypes
; ++i
)
225 info
->__base_info
[i
].__base_type
227 __cxxabiv1::__class_type_info
*>(
229 info
->__base_info
[i
].__offset_flags
230 = (__cxxabiv1::__base_class_type_info::__public_mask
231 | ((8 * i
) << __cxxabiv1::__base_class_type_info::__offset_shift
));
233 newRtti
.reset(new GeneratedPad(std::move(pad
)));
240 assert(false); // cannot happen
242 rtti
= newRtti
->get();
245 m_generatedRttis
.emplace(unoName
, std::move(newRtti
)));
246 SAL_WARN_IF( !insertion
.second
, "bridges", "key " << unoName
<< " already in generated rtti map" );
249 else // taking already generated rtti
251 rtti
= iFind2
->second
->get();
257 rtti
= iFind
->second
;
263 struct theRttiFactory
: public rtl::Static
<RTTI
, theRttiFactory
> {};
267 std::type_info
* x86_64::getRtti(typelib_TypeDescription
const & type
) {
268 return theRttiFactory::get().getRTTI(type
);
271 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */