mirror of
https://github.com/FEX-Emu/FEX.git
synced 2024-12-16 02:17:20 +00:00
f9902142f7
This will be useful to remove an indirection.
80 lines
3.0 KiB
C++
80 lines
3.0 KiB
C++
// SPDX-License-Identifier: MIT
|
|
#pragma once
|
|
|
|
#include <FEXCore/Utils/LogManager.h>
|
|
|
|
#include <cstdint>
|
|
|
|
namespace FEXCore::Utils {
|
|
|
|
/**
|
|
* @brief Casts a class's member function pointer to a raw pointer that we can JIT
|
|
*
|
|
* Has additional validation to ensure we aren't casting a class member that is invalid
|
|
*/
|
|
template <typename PointerToMemberType>
|
|
class MemberFunctionToPointerCast final {
|
|
public:
|
|
MemberFunctionToPointerCast(PointerToMemberType Function) {
|
|
memcpy(&PMF, &Function, sizeof(PMF));
|
|
}
|
|
|
|
uintptr_t GetConvertedPointer() const {
|
|
#ifdef _M_X86_64
|
|
// Itanium C++ ABI (https://itanium-cxx-abi.github.io/cxx-abi/abi.html#member-function-pointers)
|
|
// Low bit of ptr specifies if this Member function pointer is virtual or not
|
|
// Throw an assert if we were trying to cast a virtual member
|
|
LOGMAN_THROW_AA_FMT((PMF.ptr & 1) == 0, "C++ Pointer-To-Member representation didn't have low bit set to 0. Are you trying to cast a virtual member?");
|
|
#elif defined(_M_ARM_64)
|
|
// C++ ABI for the Arm 64-bit Architecture (IHI 0059E)
|
|
// 4.2.1 Representation of pointer to member function
|
|
// Differs from Itanium specification
|
|
LOGMAN_THROW_AA_FMT(PMF.adj == 0, "C++ Pointer-To-Member representation didn't have adj == 0. Are you trying to cast a virtual member?");
|
|
#else
|
|
#error Don't know how to cast Member to function here. Likely just Itanium
|
|
#endif
|
|
return PMF.ptr;
|
|
}
|
|
|
|
// Gets the vtable entry position of a virtual member function.
|
|
size_t GetVTableOffset() const {
|
|
#ifdef _M_X86_64
|
|
// Itanium C++ ABI (https://itanium-cxx-abi.github.io/cxx-abi/abi.html#member-function-pointers)
|
|
// Low bit of ptr specifies if this Member function pointer is virtual or not
|
|
// Throw an assert if we are not loading a virtual member.
|
|
LOGMAN_THROW_AA_FMT((PMF.ptr & 1) == 1, "C++ Pointer-To-Member representation didn't have low bit set to 1. This cast only works for virtual members.");
|
|
return PMF.ptr & ~1ULL;
|
|
#elif defined(_M_ARM_64)
|
|
// C++ ABI for the Arm 64-bit Architecture (IHI 0059E)
|
|
// 4.2.1 Representation of pointer to member function
|
|
// Differs from Itanium specification
|
|
LOGMAN_THROW_AA_FMT((PMF.adj & 1) == 1, "C++ Pointer-To-Member representation didn't have adj == 1. This cast only works for virtual members.");
|
|
return PMF.ptr;
|
|
#else
|
|
#error Don't know how to cast Member to function here. Likely just Itanium
|
|
#endif
|
|
}
|
|
|
|
// Gets the pointer to the vtable entry for the object passed it.
|
|
template<typename Class>
|
|
uintptr_t GetVTableEntry(Class *VirtualClass) const {
|
|
// VTable is always stored at the beginning of a class object.
|
|
uintptr_t *VTable = *reinterpret_cast<uintptr_t**>(VirtualClass);
|
|
|
|
size_t Offset = GetVTableOffset() / sizeof(void*);
|
|
return VTable[Offset];
|
|
}
|
|
|
|
private:
|
|
struct PointerToMember {
|
|
uintptr_t ptr;
|
|
uintptr_t adj;
|
|
};
|
|
|
|
PointerToMember PMF;
|
|
|
|
// Ensure the representation of PointerToMember matches
|
|
static_assert(sizeof(PMF) == sizeof(PointerToMemberType));
|
|
};
|
|
}
|