diff --git a/src/dynarmic/CMakeLists.txt b/src/dynarmic/CMakeLists.txt index de5167fc..b033e7c1 100644 --- a/src/dynarmic/CMakeLists.txt +++ b/src/dynarmic/CMakeLists.txt @@ -373,6 +373,7 @@ elseif(ARCHITECTURE STREQUAL "arm64") backend/arm64/a32_jitstate.h backend/arm64/abi.cpp backend/arm64/abi.h + backend/arm64/devirtualize.h backend/arm64/emit_arm64.cpp backend/arm64/emit_arm64.h backend/arm64/emit_arm64_a32.cpp diff --git a/src/dynarmic/backend/arm64/devirtualize.h b/src/dynarmic/backend/arm64/devirtualize.h new file mode 100644 index 00000000..edddc954 --- /dev/null +++ b/src/dynarmic/backend/arm64/devirtualize.h @@ -0,0 +1,40 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2022 MerryMage + * SPDX-License-Identifier: 0BSD + */ + +#pragma once + +#include +#include +#include + +namespace Dynarmic::Backend::Arm64 { + +struct DevirtualizedCall { + u64 fn_ptr; + u64 this_ptr; +}; + +template +DevirtualizedCall Devirtualize(mcl::class_type* this_) { + struct MemberFunctionPointer { + // Address of non-virtual function or index into vtable. + u64 ptr; + // LSB is discriminator for if function is virtual. Other bits are this adjustment. + u64 adj; + } mfp_struct = mcl::bit_cast(mfp); + + static_assert(sizeof(MemberFunctionPointer) == 16); + static_assert(sizeof(MemberFunctionPointer) == sizeof(mfp)); + + u64 fn_ptr = mfp_struct.ptr; + u64 this_ptr = mcl::bit_cast(this_) + (mfp_struct.adj >> 1); + if (mfp_struct.adj & 1) { + u64 vtable = mcl::bit_cast_pointee(this_ptr); + fn_ptr = mcl::bit_cast_pointee(vtable + fn_ptr); + } + return {fn_ptr, this_ptr}; +} + +} // namespace Dynarmic::Backend::Arm64