// license:BSD-3-Clause // copyright-holders:Couriersud #include "ppmf.h" #if PPMF_USE_MAME_DELEGATES #include "../../util/delegate.cpp" #else #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpmf-conversions" #pragma GCC diagnostic ignored "-Wpedantic" #endif namespace plib { void mfp_raw::convert_to_generic(generic_function &func, mfp_generic_class *&object) const { // apply the "this" delta to the object first // NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult,cppcoreguidelines-pro-type-reinterpret-cast) auto *o_p_delta = reinterpret_cast(reinterpret_cast(object) + m_this_delta); // if the low bit of the vtable index is clear, then it is just a raw function pointer if ((m_function & 1) == 0) { // NOLINTNEXTLINE(performance-no-int-to-ptr,cppcoreguidelines-pro-type-reinterpret-cast) func = reinterpret_cast(m_function); } else { // otherwise, it is the byte index into the vtable where the actual function lives // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) std::uint8_t *vtable_base = *reinterpret_cast(o_p_delta); if (compile_info::abi_vtable_function_descriptors::value) // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) func = reinterpret_cast(uintptr_t(vtable_base + m_function - 1)); else // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) func = *reinterpret_cast(vtable_base + m_function - 1); } object = o_p_delta; } void mfp_raw::convert_to_generic(generic_function &func, mfp_generic_class *&object) const { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) object = reinterpret_cast(reinterpret_cast(object) + (m_this_delta >> 1)); if ((m_this_delta & 1) == 0) { // NOLINTNEXTLINE(performance-no-int-to-ptr,cppcoreguidelines-pro-type-reinterpret-cast) func = reinterpret_cast(m_function); } else { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) std::uint8_t *vtable_base = *reinterpret_cast(object) + m_function; if (compile_info::abi_vtable_function_descriptors::value) // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) func = reinterpret_cast(uintptr_t(vtable_base)); else // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) func = *reinterpret_cast(vtable_base); } } struct unknown_base_equiv_novtdisp { mfp_raw::generic_function fptr; int thisdisp, vptrdisp; }; void mfp_raw::convert_to_generic(generic_function &func, mfp_generic_class *&object) const { //printf("%lx, %lx, %lx, %lx %lx\n", m_function, m_this_delta, m_vptr_offs, m_vt_index, m_size); // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) auto *byteptr = reinterpret_cast(object); // test for pointer to member function cast across virtual inheritance relationship //if ((sizeof(unknown_base_equiv) == m_size) && m_vt_index) if ((sizeof(unknown_base_equiv) == m_size) || (sizeof(unknown_base_equiv_novtdisp) == m_size)) { // add index from "this" pointer to location of vptr. This actually is an index, // it needs to be multiplied by sizeof(void *) byteptr += (m_vptr_index * static_cast(sizeof(void *))); // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) std::uint8_t const *const vptr = *reinterpret_cast(byteptr); // and add offset to virtual base from vtable if (sizeof(unknown_base_equiv) == m_size) // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) byteptr += *reinterpret_cast(vptr + m_vt_index); } // add "this" pointer displacement if present in the pointer to member function if (sizeof(single_base_equiv) < m_size) byteptr += m_this_delta; // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) object = reinterpret_cast(byteptr); // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast,performance-no-int-to-ptr) auto const *funcx = reinterpret_cast(m_function); // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast,performance-no-int-to-ptr) func = reinterpret_cast(std::uintptr_t(funcx)); } } // namespace plib #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic pop #endif #endif