diff options
author | 2021-09-22 05:05:19 +1000 | |
---|---|---|
committer | 2021-09-22 05:05:19 +1000 | |
commit | 86c005377d62adf7996f3d6def3046e3fde1da27 (patch) | |
tree | 8f4ac56e77d3d2cc250fb8be4e3627404aafefcb /src/lib/util/delegate.cpp | |
parent | a0289bfd4c041a780440e1d1e0055b531069dd50 (diff) |
cpu/drcbex64.cpp: Proof-of-concept for optimisation of calling out.
Resolve address space virtual member function addresses on constrcution
and call them directly. Provides a small but measurable improvement to
performance in drivers that use the recompiler and access the memory
system a lot.
Also made MSVC delegates capable of walking past all the thunks MSVC
puts in the way of actually calling a member function. I'm not
accounting for the "this" pointer being passed in RDX when the return
value is an oversize scalar. This is harmless because it won't see
anything that looks like a virtual call thunk using RCX when RCX points
to uninitialised space for the return value. It just means virtual
member function calls won't be bypassed if the return value is an
oversize scalar, but that doesn't happen frequently anyway.
Diffstat (limited to 'src/lib/util/delegate.cpp')
-rw-r--r-- | src/lib/util/delegate.cpp | 42 |
1 files changed, 40 insertions, 2 deletions
diff --git a/src/lib/util/delegate.cpp b/src/lib/util/delegate.cpp index 33d5f8d54e8..346ba1283a0 100644 --- a/src/lib/util/delegate.cpp +++ b/src/lib/util/delegate.cpp @@ -113,10 +113,11 @@ delegate_generic_function delegate_mfp_itanium::convert_to_generic(delegate_gene //------------------------------------------------- // delegate_mfp_msvc::adjust_this_pointer - given // an object pointer and member function pointer, -// apply the displacement +// apply the displacement, and walk past +// recognisable thunks //------------------------------------------------- -void delegate_mfp_msvc::adjust_this_pointer(delegate_generic_class *&object) const +delegate_generic_function delegate_mfp_msvc::adjust_this_pointer(delegate_generic_class *&object) const { LOG("Input this=%p ", reinterpret_cast<void const *>(object)); if (sizeof(single_base_equiv) < m_size) @@ -124,16 +125,53 @@ void delegate_mfp_msvc::adjust_this_pointer(delegate_generic_class *&object) con if (sizeof(unknown_base_equiv) == m_size) LOG("vptrdelta=%d vindex=%d ", m_vptr_offs, m_vt_index); std::uint8_t *byteptr = reinterpret_cast<std::uint8_t *>(object); + + // test for pointer to member function cast across virtual inheritance relationship if ((sizeof(unknown_base_equiv) == m_size) && m_vt_index) { + // add offset from "this" pointer to location of vptr, and add offset to virtual base from vtable byteptr += m_vptr_offs; std::uint8_t const *const vptr = *reinterpret_cast<std::uint8_t const *const *>(byteptr); byteptr += *reinterpret_cast<int const *>(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; LOG("Calculated this=%p\n", reinterpret_cast<void const *>(byteptr)); object = reinterpret_cast<delegate_generic_class *>(byteptr); + + // walk past recognisable thunks + std::uint8_t const *func = reinterpret_cast<std::uint8_t const *>(m_function); +#if defined(__x86_64__) || defined(_M_X64) + while (true) + { + if (0xe9 == func[0]) + { + // absolute jump with 32-bit displacement + LOG("Found relative jump at %p ", func); + func += 5 + *reinterpret_cast<std::int32_t const *>(func + 1); + LOG("redirecting to %p\n", func); + } + else if ((0x48 == func[0]) && (0x8b == func[1]) && (0x01 == func[2]) && (0xff == func[3]) && ((0x60 == func[4]) || (0xa0 == func[4]))) + { + // virtual function call thunk - mov rax,QWORD PTR [rcx] ; jmp QWORD PTR [rax+...] + LOG("Found virtual member function thunk at %p ", func); + std::uint8_t const *const vptr = *reinterpret_cast<std::uint8_t const *const *>(object); + if (0x60 == func[4]) + func = *reinterpret_cast<std::uint8_t const *const *>(vptr + *reinterpret_cast<std::int8_t const *>(func + 5)); + else + func = *reinterpret_cast<std::uint8_t const *const *>(vptr + *reinterpret_cast<std::int32_t const *>(func + 5)); + LOG("redirecting to %p\n", func); + } + else + { + // not something we can easily bypass + break; + } + } +#endif + return reinterpret_cast<delegate_generic_function>(std::uintptr_t(func)); } } // namespace util::detail |