From e5ace3756085132d60f855936995b6331b3f04e4 Mon Sep 17 00:00:00 2001
From: MerryMage <MerryMage@users.noreply.github.com>
Date: Mon, 8 Jan 2018 18:33:42 +0000
Subject: [PATCH] a64_emit_x64: Call interpreter

---
 src/backend_x64/a64_emit_x64.cpp | 10 +++++----
 src/backend_x64/devirtualize.h   | 38 ++++++++++++++++++++++++++++++++
 src/common/mp.h                  |  8 +++++++
 3 files changed, 52 insertions(+), 4 deletions(-)
 create mode 100644 src/backend_x64/devirtualize.h

diff --git a/src/backend_x64/a64_emit_x64.cpp b/src/backend_x64/a64_emit_x64.cpp
index 78701559..db4ceeeb 100644
--- a/src/backend_x64/a64_emit_x64.cpp
+++ b/src/backend_x64/a64_emit_x64.cpp
@@ -11,6 +11,7 @@
 #include "backend_x64/a64_jitstate.h"
 #include "backend_x64/abi.h"
 #include "backend_x64/block_of_code.h"
+#include "backend_x64/devirtualize.h"
 #include "backend_x64/emit_x64.h"
 #include "common/address_range.h"
 #include "common/assert.h"
@@ -220,11 +221,12 @@ void A64EmitX64::EmitA64SetPC(A64EmitContext& ctx, IR::Inst* inst) {
 }
 
 void A64EmitX64::EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDescriptor) {
-    code->mov(code->ABI_PARAM1, A64::LocationDescriptor{terminal.next}.PC());
-    code->mov(code->ABI_PARAM2.cvt32(), 1);
-    code->mov(qword[r15 + offsetof(A64JitState, pc)], code->ABI_PARAM1.cvt32());
+    //code->mov(qword[r15 + offsetof(A64JitState, pc)], code->ABI_PARAM1.cvt32());
     code->SwitchMxcsrOnExit();
-    //code->CallFunction(cb.InterpreterFallback);
+    Devirtualize<&A64::UserCallbacks::InterpreterFallback>(conf.callbacks).EmitCall(code, [&](Xbyak::Reg64 param1, Xbyak::Reg64 param2){
+        code->mov(param1, A64::LocationDescriptor{terminal.next}.PC());
+        code->mov(param2.cvt32(), 1);
+    });
     code->ReturnFromRunCode(true); // TODO: Check cycles
 }
 
diff --git a/src/backend_x64/devirtualize.h b/src/backend_x64/devirtualize.h
new file mode 100644
index 00000000..78e27df7
--- /dev/null
+++ b/src/backend_x64/devirtualize.h
@@ -0,0 +1,38 @@
+/* This file is part of the dynarmic project.
+ * Copyright (c) 2018 MerryMage
+ * This software may be used and distributed according to the terms of the GNU
+ * General Public License version 2 or any later version.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include "backend_x64/callback.h"
+#include "common/common_types.h"
+#include "common/mp.h"
+
+namespace Dynarmic {
+namespace BackendX64 {
+
+namespace impl {
+
+template <auto fn, typename F>
+struct ThunkBuilder;
+
+template <auto fn, typename C, typename R, typename... Args>
+struct ThunkBuilder<fn, R(C::*)(Args...)> {
+    static R Thunk(C* this_, Args... args) {
+        return (this_->*fn)(std::forward<Args>(args)...);
+    }
+};
+
+} // namespace impl
+
+template <auto fn>
+ArgCallback Devirtualize(mp::class_type_t<decltype(fn)>* this_) {
+    return ArgCallback{&impl::ThunkBuilder<fn, decltype(fn)>::Thunk, reinterpret_cast<u64>(this_)};
+}
+
+} // namespace BackendX64
+} // namespace Dynarmic
diff --git a/src/common/mp.h b/src/common/mp.h
index b624867f..10ca0e82 100644
--- a/src/common/mp.h
+++ b/src/common/mp.h
@@ -72,5 +72,13 @@ using parameter_type_t = typename FunctionInfo<Function>::template Parameter<Par
 template <typename Function>
 using return_type_t = typename FunctionInfo<Function>::return_type;
 
+/**
+ * Helper template for retrieving the class type of a member function.
+ *
+ * @tparam Function The function type to get the return type of.
+ */
+template <typename Function>
+using class_type_t = typename FunctionInfo<Function>::class_type;
+
 } // namespace mp
 } // namespace Dynarmic