ctor_dtor.hpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  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. // For more information, see http://www.boost.org
  7. #ifndef BOOST_DLL_DETAIL_CTOR_DTOR_HPP_
  8. #define BOOST_DLL_DETAIL_CTOR_DTOR_HPP_
  9. #include <boost/dll/config.hpp>
  10. #ifdef BOOST_HAS_PRAGMA_ONCE
  11. # pragma once
  12. #endif
  13. #include <boost/dll/detail/aggressive_ptr_cast.hpp>
  14. #include <boost/dll/detail/get_mem_fn_type.hpp>
  15. #if defined(BOOST_MSVC) || defined(BOOST_MSVC_VER)
  16. # include <boost/dll/detail/demangling/msvc.hpp>
  17. #else
  18. # include <boost/dll/detail/demangling/itanium.hpp>
  19. #endif
  20. namespace boost { namespace dll { namespace detail {
  21. /*!
  22. * This class stores a constructor.
  23. *
  24. * In some compilers there are several constructors in code, which may include an allocating one.
  25. * This can be used if the imported class shall be put on the heap, which is why the class provied both types.
  26. */
  27. template<typename Signature>
  28. struct constructor;
  29. template<typename Class, typename ...Args>
  30. struct constructor<Class(Args...)> {
  31. typedef typename detail::get_mem_fn_type<Class, void(Args...)>::mem_fn standard_t;
  32. typedef Class*(*allocating_t)(Args...);
  33. //! The standard, i.e. not allocating constructor. @warning May differ with the compiler. Use @ref constructor::call_standard instead.
  34. standard_t standard;
  35. //! The allocating constructor. @warning May differ with the compiler. Use @ref constructor::call_allocating instead.
  36. allocating_t allocating;
  37. //! Call the standard constructor
  38. void call_standard (Class * const ptr, Args...args){ (ptr->*standard)(static_cast<Args>(args)...); }
  39. //! Call the deleting destructor
  40. Class * call_allocating(Args...args){ return allocating(static_cast<Args>(args)...); }
  41. //! True if a allocating constructor could be loaded.
  42. bool has_allocating() const { return allocating != nullptr; }
  43. //! True if a standard constructor could be loaded.
  44. bool has_standard() const { return standard != nullptr; }
  45. //! False if neither the allocating nor the standard constructor is available.
  46. bool is_empty() const { return (allocating == nullptr) && (standard == nullptr) ; }
  47. constructor() = delete;
  48. constructor(const constructor &) = default;
  49. explicit constructor(standard_t standard, allocating_t allocating = nullptr)
  50. : standard(standard)
  51. , allocating(allocating)
  52. {}
  53. };
  54. template <typename Class>
  55. struct destructor {
  56. #if !defined(_WIN32)
  57. typedef void(*type)(Class* const);
  58. #elif !defined(_WIN64)
  59. typedef void(__thiscall * type)(Class* const);
  60. #else
  61. typedef void(__cdecl * type)(Class* const);
  62. #endif
  63. typedef type standard_t;
  64. typedef type deleting_t;
  65. //! The standard, i.e. not deleting destructor. @warning May differ with the compiler. Use @ref destructor::call_standard instead.
  66. standard_t standard;
  67. //! The deleting destructor. @warning May differ with the compiler. Use @ref destructor::call_deallocating instead.
  68. deleting_t deleting;
  69. //! Call the standard constructor
  70. void call_standard(Class * const ptr){ standard(ptr); }
  71. //! Call the deleting destructor
  72. void call_deleting(Class * const ptr){ deleting(ptr); }
  73. //! True if a deleting destructor could be loaded.
  74. bool has_deleting() const { return deleting != nullptr; }
  75. //! True if a standard destructor could be loaded.
  76. bool has_standard() const { return standard != nullptr; }
  77. //! False if neither the deleting nor the standard destructor is available.
  78. bool is_empty() const { return (deleting == nullptr) && (standard == nullptr) ; }
  79. destructor() = delete;
  80. //! Copy destructor.
  81. destructor(const destructor &) = default;
  82. //! Construct it from both the standard destructor and the allocating destructor
  83. explicit destructor(const standard_t &standard, const deleting_t &deleting = nullptr)
  84. : standard(standard)
  85. , deleting(deleting)
  86. {}
  87. };
  88. #if defined(BOOST_MSVC) || defined(BOOST_MSVC_VER)
  89. template<typename Signature, typename Lib>
  90. constructor<Signature> load_ctor(Lib & lib, const mangled_storage_impl::ctor_sym & ct) {
  91. typedef typename constructor<Signature>::standard_t standard_t;
  92. standard_t ctor = lib.template get<standard_t>(ct);
  93. return constructor<Signature>(ctor);
  94. }
  95. template<typename Class, typename Lib>
  96. destructor<Class> load_dtor(Lib & lib, const mangled_storage_impl::dtor_sym & dt) {
  97. typedef typename destructor<Class>::standard_t standard_t;
  98. //@apolukhin That does NOT work this way with MSVC-14 x32 via memcpy. The x64 is different.
  99. //standard_t dtor = &lib.template get< typename boost::remove_pointer<standard_t>::type >(dt);
  100. void * buf = &lib.template get<unsigned char>(dt);
  101. standard_t dtor;
  102. std::memcpy(&dtor, &buf, sizeof(dtor));
  103. return destructor<Class>(dtor);
  104. }
  105. #else
  106. template<typename Signature, typename Lib>
  107. constructor<Signature> load_ctor(Lib & lib, const mangled_storage_impl::ctor_sym & ct) {
  108. typedef typename constructor<Signature>::standard_t stand;
  109. typedef typename constructor<Signature>::allocating_t alloc;
  110. stand s = nullptr;
  111. alloc a = nullptr;
  112. //see here for the abi http://mentorembedded.github.io/cxx-abi/abi.html#mangling-special-ctor-dtor
  113. if (!ct.C1.empty())
  114. {
  115. //the only way this works on mingw/win.
  116. //For some reason there is always an 0xA in the following poniter, which screws with the this pointer.
  117. void *buf = &lib.template get<unsigned char>(ct.C1);
  118. std::memcpy(&s, &buf, sizeof(void*));
  119. }
  120. if (!ct.C3.empty())
  121. {
  122. void *buf = &lib.template get<unsigned char>(ct.C3);
  123. std::memcpy(&a, &buf, sizeof(void*));
  124. }
  125. return constructor<Signature>(s,a);
  126. }
  127. template<typename Class, typename Lib>
  128. destructor<Class> load_dtor(Lib & lib, const mangled_storage_impl::dtor_sym & dt) {
  129. typedef typename destructor<Class>::standard_t stand;
  130. typedef typename destructor<Class>::deleting_t delet;
  131. stand s = nullptr;
  132. delet d = nullptr;
  133. //see here for the abi http://mentorembedded.github.io/cxx-abi/abi.html#mangling-special-ctor-dtor
  134. if (!dt.D1.empty()) {
  135. s = &lib.template get< typename boost::remove_pointer<stand>::type >(dt.D1);
  136. }
  137. if (!dt.D0.empty()) {
  138. d = &lib.template get< typename boost::remove_pointer<delet>::type >(dt.D0);
  139. }
  140. return destructor<Class>(s,d);
  141. }
  142. #endif
  143. }}} // namespace boost::dll::detail
  144. #endif /* BOOST_DLL_DETAIL_CTOR_DTOR_HPP_ */