117 lines
4.5 KiB
C#
117 lines
4.5 KiB
C#
using System;
|
|
using System.Reflection;
|
|
using SRE = System.Reflection.Emit;
|
|
using CIL = Mono.Cecil.Cil;
|
|
using System.Linq.Expressions;
|
|
using MonoMod.Utils;
|
|
using System.Collections.Generic;
|
|
|
|
namespace MonoMod.Utils {
|
|
public static class DynamicMethodHelper {
|
|
|
|
// Used in EmitReference.
|
|
private static List<object> References = new List<object>();
|
|
public static object GetReference(int id) => References[id];
|
|
public static void SetReference(int id, object obj) => References[id] = obj;
|
|
private static int AddReference(object obj) {
|
|
lock (References) {
|
|
References.Add(obj);
|
|
return References.Count - 1;
|
|
}
|
|
}
|
|
public static void FreeReference(int id) => References[id] = null;
|
|
|
|
private static readonly MethodInfo _GetMethodFromHandle = typeof(MethodBase).GetMethod("GetMethodFromHandle", new Type[] { typeof(RuntimeMethodHandle) });
|
|
private static readonly MethodInfo _GetReference = typeof(DynamicMethodHelper).GetMethod("GetReference");
|
|
|
|
/// <summary>
|
|
/// Fill the DynamicMethod with a stub.
|
|
/// </summary>
|
|
public static SRE.DynamicMethod Stub(this SRE.DynamicMethod dm) {
|
|
SRE.ILGenerator il = dm.GetILGenerator();
|
|
for (int i = 0; i < 10; i++) {
|
|
// Prevent mono from inlining the DynamicMethod.
|
|
il.Emit(SRE.OpCodes.Nop);
|
|
}
|
|
if (dm.ReturnType != typeof(void)) {
|
|
il.DeclareLocal(dm.ReturnType);
|
|
il.Emit(SRE.OpCodes.Ldloca_S, (sbyte) 0);
|
|
il.Emit(SRE.OpCodes.Initobj, dm.ReturnType);
|
|
il.Emit(SRE.OpCodes.Ldloc_0);
|
|
}
|
|
il.Emit(SRE.OpCodes.Ret);
|
|
return dm;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fill the DynamicMethod with a stub.
|
|
/// </summary>
|
|
public static DynamicMethodDefinition Stub(this DynamicMethodDefinition dmd) {
|
|
CIL.ILProcessor il = dmd.GetILProcessor();
|
|
for (int i = 0; i < 10; i++) {
|
|
// Prevent mono from inlining the DynamicMethod.
|
|
il.Emit(CIL.OpCodes.Nop);
|
|
}
|
|
if (dmd.Definition.ReturnType != dmd.Definition.Module.TypeSystem.Void) {
|
|
il.Body.Variables.Add(new CIL.VariableDefinition(dmd.Definition.ReturnType));
|
|
il.Emit(CIL.OpCodes.Ldloca_S, (sbyte) 0);
|
|
il.Emit(CIL.OpCodes.Initobj, dmd.Definition.ReturnType);
|
|
il.Emit(CIL.OpCodes.Ldloc_0);
|
|
}
|
|
il.Emit(CIL.OpCodes.Ret);
|
|
return dmd;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Emit a reference to an arbitrary object. Note that the references "leak."
|
|
/// </summary>
|
|
public static int EmitReference<T>(this SRE.ILGenerator il, T obj) {
|
|
Type t = typeof(T);
|
|
int id = AddReference(obj);
|
|
il.Emit(SRE.OpCodes.Ldc_I4, id);
|
|
il.Emit(SRE.OpCodes.Call, _GetReference);
|
|
if (t.GetTypeInfo().IsValueType)
|
|
il.Emit(SRE.OpCodes.Unbox_Any, t);
|
|
return id;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Emit a reference to an arbitrary object. Note that the references "leak."
|
|
/// </summary>
|
|
public static int EmitReference<T>(this CIL.ILProcessor il, T obj) {
|
|
Type t = typeof(T);
|
|
int id = AddReference(obj);
|
|
il.Emit(CIL.OpCodes.Ldc_I4, id);
|
|
il.Emit(CIL.OpCodes.Call, _GetReference);
|
|
if (t.GetTypeInfo().IsValueType)
|
|
il.Emit(CIL.OpCodes.Unbox_Any, t);
|
|
return id;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Emit a reference to an arbitrary object. Note that the references "leak."
|
|
/// </summary>
|
|
public static int EmitGetReference<T>(this SRE.ILGenerator il, int id) {
|
|
Type t = typeof(T);
|
|
il.Emit(SRE.OpCodes.Ldc_I4, id);
|
|
il.Emit(SRE.OpCodes.Call, _GetReference);
|
|
if (t.GetTypeInfo().IsValueType)
|
|
il.Emit(SRE.OpCodes.Unbox_Any, t);
|
|
return id;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Emit a reference to an arbitrary object. Note that the references "leak."
|
|
/// </summary>
|
|
public static int EmitGetReference<T>(this CIL.ILProcessor il, int id) {
|
|
Type t = typeof(T);
|
|
il.Emit(CIL.OpCodes.Ldc_I4, id);
|
|
il.Emit(CIL.OpCodes.Call, _GetReference);
|
|
if (t.GetTypeInfo().IsValueType)
|
|
il.Emit(CIL.OpCodes.Unbox_Any, t);
|
|
return id;
|
|
}
|
|
|
|
}
|
|
}
|