diff --git a/BizHawk.Common/Extensions/ReflectionExtensions.cs b/BizHawk.Common/Extensions/ReflectionExtensions.cs
index 67fc2500ad..b2306ac221 100644
--- a/BizHawk.Common/Extensions/ReflectionExtensions.cs
+++ b/BizHawk.Common/Extensions/ReflectionExtensions.cs
@@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Reflection;
+using System.Reflection.Emit;
+using System.Runtime.InteropServices;
namespace BizHawk.Common.ReflectionExtensions
{
@@ -160,5 +162,49 @@ namespace BizHawk.Common.ReflectionExtensions
{
return (T)o.GetType().GetCustomAttributes(typeof(T), false)[0];
}
+
+ ///
+ /// where the fields begin relative to the address an object references points to
+ ///
+ public static IntPtr ManagedFieldStart { get { return _managedfieldstart; } }
+
+ [StructLayout(LayoutKind.Explicit)]
+ private class Junkus { [FieldOffset(0)]public IntPtr s; }
+
+ static IntPtr _managedfieldstart = GetManagedOffset(typeof(Junkus).GetField("s"));
+
+ ///
+ /// the address of a field relative to the address an object reference of that type points to. this function is very expensive to call.
+ ///
+ ///
+ ///
+ public static IntPtr GetManagedOffset(this FieldInfo field)
+ {
+ Type type = field.DeclaringType;
+
+ var dyn = new System.Reflection.Emit.DynamicMethod(
+ "xxz0", typeof(IntPtr), new Type[] { typeof(object) }, typeof(ReflectionExtensions).Module, true);
+ var il = dyn.GetILGenerator();
+
+ var pin = il.DeclareLocal(type, true);
+ var baseaddr = il.DeclareLocal(typeof(IntPtr));
+
+ il.Emit(OpCodes.Ldarg_0);
+ il.Emit(OpCodes.Stloc, pin); // force cast object to type (invalid), and pin
+
+ il.Emit(OpCodes.Ldloc, pin); // base address of reference (points to typeinfo)
+ il.Emit(OpCodes.Conv_I); // convert object ref to intptr (invalid)
+ il.Emit(OpCodes.Stloc, baseaddr);
+
+ il.Emit(OpCodes.Ldloc, pin);
+ il.Emit(OpCodes.Ldflda, field); // address of desired field
+ il.Emit(OpCodes.Conv_I); // convert field& to intptr (invalid)
+ il.Emit(OpCodes.Ldloc, baseaddr);
+ il.Emit(OpCodes.Sub);
+ il.Emit(OpCodes.Ret);
+
+ return (IntPtr)dyn.Invoke(null, new object[] { new object() });
+ }
+
}
}