| 1 | // Copyright 2016 Klemens Morgenstern, Antony Polukhin |
| 2 | // |
| 3 | // Distributed under the Boost Software License, Version 1.0. |
| 4 | // (See accompanying file LICENSE_1_0.txt |
| 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) |
| 6 | |
| 7 | // For more information, see http://www.boost.org |
| 8 | |
| 9 | #ifndef BOOST_DLL_DETAIL_CTOR_DTOR_HPP_ |
| 10 | #define BOOST_DLL_DETAIL_CTOR_DTOR_HPP_ |
| 11 | |
| 12 | #include <boost/dll/config.hpp> |
| 13 | #ifdef BOOST_HAS_PRAGMA_ONCE |
| 14 | # pragma once |
| 15 | #endif |
| 16 | |
| 17 | #include <boost/dll/detail/aggressive_ptr_cast.hpp> |
| 18 | #include <boost/dll/detail/get_mem_fn_type.hpp> |
| 19 | |
| 20 | #if defined(_MSC_VER) // MSVC, Clang-cl, and ICC on Windows |
| 21 | # include <boost/dll/detail/demangling/msvc.hpp> |
| 22 | #else |
| 23 | # include <boost/dll/detail/demangling/itanium.hpp> |
| 24 | #endif |
| 25 | |
| 26 | |
| 27 | namespace boost { namespace dll { namespace detail { |
| 28 | |
| 29 | /*! |
| 30 | * This class stores a constructor. |
| 31 | * |
| 32 | * In some compilers there are several constructors in code, which may include an allocating one. |
| 33 | * This can be used if the imported class shall be put on the heap, which is why the class provied both types. |
| 34 | */ |
| 35 | template<typename Signature> |
| 36 | struct constructor; |
| 37 | |
| 38 | template<typename Class, typename ...Args> |
| 39 | struct constructor<Class(Args...)> { |
| 40 | typedef typename detail::get_mem_fn_type<Class, void(Args...)>::mem_fn standard_t; |
| 41 | typedef Class*(*allocating_t)(Args...); |
| 42 | |
| 43 | |
| 44 | //! The standard, i.e. not allocating constructor. @warning May differ with the compiler. Use @ref constructor::call_standard instead. |
| 45 | standard_t standard; |
| 46 | //! The allocating constructor. @warning May differ with the compiler. Use @ref constructor::call_allocating instead. |
| 47 | allocating_t allocating; |
| 48 | |
| 49 | //! Call the standard constructor |
| 50 | void call_standard (Class * const ptr, Args...args){ (ptr->*standard)(static_cast<Args>(args)...); } |
| 51 | |
| 52 | //! Call the deleting destructor |
| 53 | Class * call_allocating(Args...args){ return allocating(static_cast<Args>(args)...); } |
| 54 | |
| 55 | |
| 56 | //! True if a allocating constructor could be loaded. |
| 57 | bool has_allocating() const { return allocating != nullptr; } |
| 58 | |
| 59 | //! True if a standard constructor could be loaded. |
| 60 | bool has_standard() const { return standard != nullptr; } |
| 61 | |
| 62 | //! False if neither the allocating nor the standard constructor is available. |
| 63 | bool is_empty() const { return (allocating == nullptr) && (standard == nullptr) ; } |
| 64 | |
| 65 | constructor() = delete; |
| 66 | constructor(const constructor &) = default; |
| 67 | |
| 68 | explicit constructor(standard_t standard, allocating_t allocating = nullptr) |
| 69 | : standard(standard) |
| 70 | , allocating(allocating) |
| 71 | {} |
| 72 | }; |
| 73 | |
| 74 | |
| 75 | |
| 76 | template <typename Class> |
| 77 | struct destructor { |
| 78 | #if !defined(_WIN32) |
| 79 | typedef void(*type)(Class* const); |
| 80 | #elif !defined(_WIN64) |
| 81 | typedef void(__thiscall * type)(Class* const); |
| 82 | #else |
| 83 | typedef void(__cdecl * type)(Class* const); |
| 84 | #endif |
| 85 | |
| 86 | typedef type standard_t; |
| 87 | typedef type deleting_t; |
| 88 | |
| 89 | //! The standard, i.e. not deleting destructor. @warning May differ with the compiler. Use @ref destructor::call_standard instead. |
| 90 | standard_t standard; |
| 91 | //! The deleting destructor. @warning May differ with the compiler. Use @ref destructor::call_deallocating instead. |
| 92 | deleting_t deleting; |
| 93 | |
| 94 | //! Call the standard constructor |
| 95 | void call_standard(Class * const ptr){ standard(ptr); } |
| 96 | |
| 97 | //! Call the deleting destructor |
| 98 | void call_deleting(Class * const ptr){ deleting(ptr); } |
| 99 | |
| 100 | //! True if a deleting destructor could be loaded. |
| 101 | bool has_deleting() const { return deleting != nullptr; } |
| 102 | |
| 103 | //! True if a standard destructor could be loaded. |
| 104 | bool has_standard() const { return standard != nullptr; } |
| 105 | |
| 106 | //! False if neither the deleting nor the standard destructor is available. |
| 107 | bool is_empty() const { return (deleting == nullptr) && (standard == nullptr) ; } |
| 108 | destructor() = delete; |
| 109 | |
| 110 | //! Copy destructor. |
| 111 | destructor(const destructor &) = default; |
| 112 | |
| 113 | //! Construct it from both the standard destructor and the allocating destructor |
| 114 | explicit destructor(const standard_t &standard, const deleting_t &deleting = nullptr) |
| 115 | : standard(standard) |
| 116 | , deleting(deleting) |
| 117 | {} |
| 118 | }; |
| 119 | |
| 120 | #if defined(_MSC_VER) // MSVC, Clang-cl, and ICC on Windows |
| 121 | |
| 122 | template<typename Signature, typename Lib> |
| 123 | constructor<Signature> load_ctor(Lib & lib, const mangled_storage_impl::ctor_sym & ct) { |
| 124 | typedef typename constructor<Signature>::standard_t standard_t; |
| 125 | standard_t ctor = lib.template get<standard_t>(ct); |
| 126 | return constructor<Signature>(ctor); |
| 127 | } |
| 128 | |
| 129 | template<typename Class, typename Lib> |
| 130 | destructor<Class> load_dtor(Lib & lib, const mangled_storage_impl::dtor_sym & dt) { |
| 131 | typedef typename destructor<Class>::standard_t standard_t; |
| 132 | //@apolukhin That does NOT work this way with MSVC-14 x32 via memcpy. The x64 is different. |
| 133 | //standard_t dtor = &lib.template get< typename boost::remove_pointer<standard_t>::type >(dt); |
| 134 | void * buf = &lib.template get<unsigned char>(dt); |
| 135 | standard_t dtor; |
| 136 | std::memcpy(&dtor, &buf, sizeof(dtor)); |
| 137 | return destructor<Class>(dtor); |
| 138 | } |
| 139 | |
| 140 | #else |
| 141 | |
| 142 | template<typename Signature, typename Lib> |
| 143 | constructor<Signature> load_ctor(Lib & lib, const mangled_storage_impl::ctor_sym & ct) { |
| 144 | typedef typename constructor<Signature>::standard_t stand; |
| 145 | typedef typename constructor<Signature>::allocating_t alloc; |
| 146 | |
| 147 | stand s = nullptr; |
| 148 | alloc a = nullptr; |
| 149 | |
| 150 | //see here for the abi http://mentorembedded.github.io/cxx-abi/abi.html#mangling-special-ctor-dtor |
| 151 | |
| 152 | if (!ct.C1.empty()) |
| 153 | { |
| 154 | //the only way this works on mingw/win. |
| 155 | //For some reason there is always an 0xA in the following poniter, which screws with the this pointer. |
| 156 | void *buf = &lib.template get<unsigned char>(ct.C1); |
| 157 | std::memcpy(dest: &s, src: &buf, n: sizeof(void*)); |
| 158 | } |
| 159 | if (!ct.C3.empty()) |
| 160 | { |
| 161 | void *buf = &lib.template get<unsigned char>(ct.C3); |
| 162 | std::memcpy(dest: &a, src: &buf, n: sizeof(void*)); |
| 163 | } |
| 164 | |
| 165 | return constructor<Signature>(s,a); |
| 166 | } |
| 167 | |
| 168 | template<typename Class, typename Lib> |
| 169 | destructor<Class> load_dtor(Lib & lib, const mangled_storage_impl::dtor_sym & dt) { |
| 170 | typedef typename destructor<Class>::standard_t stand; |
| 171 | typedef typename destructor<Class>::deleting_t delet; |
| 172 | |
| 173 | stand s = nullptr; |
| 174 | delet d = nullptr; |
| 175 | |
| 176 | //see here for the abi http://mentorembedded.github.io/cxx-abi/abi.html#mangling-special-ctor-dtor |
| 177 | if (!dt.D1.empty()) { |
| 178 | s = &lib.template get< typename boost::remove_pointer<stand>::type >(dt.D1); |
| 179 | } |
| 180 | |
| 181 | if (!dt.D0.empty()) { |
| 182 | d = &lib.template get< typename boost::remove_pointer<delet>::type >(dt.D0); |
| 183 | } |
| 184 | |
| 185 | return destructor<Class>(s,d); |
| 186 | |
| 187 | } |
| 188 | |
| 189 | #endif |
| 190 | |
| 191 | }}} // namespace boost::dll::detail |
| 192 | |
| 193 | #endif /* BOOST_DLL_DETAIL_CTOR_DTOR_HPP_ */ |
| 194 | |