public void Register(Type type) { var atr = type.GetCustomAttribute(typeof(SubscribeAttribute)); if (atr == null) { return; } var methods = type.GetMethods(); foreach (var m in methods) { var atr2 = m.GetCustomAttribute(typeof(SubscribeAttribute)); if (atr2 == null) { continue; } var ed = CreateEventDeclare(atr2 as SubscribeAttribute, m); ed.ServiceInstanceType = type; ed.ServiceInstanceCtor2 = DynamicMethodHelper.CreateCtorFunc <Func <object> >(type, Type.EmptyTypes); if (eventRegister.ContainsKey(ed.Name)) { throw new Exception($"已注册过相同的事件名 {ed.Name}"); } eventRegister.Add(ed.Name, ed); if (ed.IsArray)//集合重新创建一个事件定义 { var clone = ed.Clone() as EventDeclare; clone.IsCopy = true; eventRegister.Add(clone.GetArrayName(), clone); } } }
private static bool GetFieldAccessors <T>(string name, bool writeAlso, out Func <StringBuilder, T> getter, out Action <StringBuilder, T> setter) { var field = typeof(StringBuilder).GetField(name, BindingFlags.NonPublic | BindingFlags.Instance); if (field == null) { getter = null; setter = null; return(false); } var method = new DynamicMethodHelper(name + "_StringBuilder_getter", typeof(T), new[] { typeof(StringBuilder) }, typeof(StringBuilder)); method.GetField(0, field); method.Return(); getter = method.Compile <Func <StringBuilder, T> >(); if (writeAlso) { method = new DynamicMethodHelper(name + "_StringBuilder_setter", null, new[] { typeof(StringBuilder), typeof(T) }, typeof(StringBuilder)); method.PushArg(0); method.PushArg(1); method.SetField(field); method.Return(); setter = method.Compile <Action <StringBuilder, T> >(); } else { setter = null; } return(true); }
static StringBuilderInternalAccessor() { var method = typeof(string).GetMethod("FastAllocateString", BindingFlags.NonPublic | BindingFlags.Static); var dynamic = new DynamicMethodHelper("FastAllocateString_String_caller", typeof(string), new[] { typeof(int) }, typeof(string)); dynamic.PushArg(0); dynamic.CallMethod(method); dynamic.Return(); _stringAllocator = dynamic.Compile <Func <int, string> >(); Action <StringBuilder, string> dummySetter; if (GetFieldAccessors("m_StringValue", false, out _stringValueGetter, out dummySetter)) { _instance = new StringBuilderInternalAccessorOriginal(); } else { GetFieldAccessors("m_ChunkPrevious", true, out _previousGetter, out _previousSetter); GetFieldAccessors("m_ChunkChars", true, out _charsGetter, out _charsSetter); GetFieldAccessors("m_ChunkOffset", true, out _offsetGetter, out _offsetSetter); GetFieldAccessors("m_ChunkLength", true, out _lengthGetter, out _lengthSetter); _instance = new StringBuilderInternalAccessor40(); } }
public void EmitConstructorInvokerInvokeWithParametersComplexTypes() { Type personType = typeof(Person); Type[] parameterTypes = { typeof(string), typeof(string), typeof(int), typeof(Child) }; ConstructorInvoker constructorInvoker = DynamicMethodHelper.EmitConstructorInvoker( personType, personType.GetConstructor( BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, parameterTypes, null), parameterTypes); const string name = "javier"; const string surname = "sotomayor"; const int age = 45; const string childName = "child"; Child child = new Child(childName); Person person = (Person)constructorInvoker(name, surname, age, child); Assert.IsNotNull(person); Assert.AreEqual(name, person.Name); Assert.AreEqual(surname, person.Surname); Assert.AreEqual(age, person.Age); Assert.IsNotNull(person.Child); Assert.AreSame(child, person.Child); Assert.AreEqual(childName, person.Child.Name); }
public void EmitMethodInvokerInvokeStaticMethod() { MethodInfo methodInfo = typeof(MathHelper).GetMethod("Pow", new[] { typeof(double), typeof(double) }); MethodInvoker methodInvoker = DynamicMethodHelper.EmitMethodInvoker(typeof(MathHelper), methodInfo); object result = methodInvoker(null, Convert.ChangeType(10, TypeCode.Double), Convert.ChangeType(2, TypeCode.Double)); Assert.AreEqual(MathHelper.Pow(10, 2), result); }
public void EmitMethodInvokerInvokeMethodWithReturnType() { Type[] parameterTypes = { typeof(int), typeof(int) }; MathHelper mathHelper = new MathHelper(); object value = DynamicMethodHelper.EmitMethodInvoker(typeof(MathHelper), typeof(MathHelper).GetMethod("Sum", parameterTypes))(mathHelper, 10, 5); Assert.AreEqual(mathHelper.Sum(10, 5), (int)value); }
public object Invoke(object[] parameters) { if (delgate != null) { return(delgate(parameters)); } this.delgate = DynamicMethodHelper.CreateDynamicConstructorInfoHandler(type, info); return(this.delgate(parameters)); }
public object GetValue(object obj, object[] index) { if (this.getDelegate != null) { return(this.getDelegate(obj, index)); } this.getDelegate = DynamicMethodHelper.CreateGetHandler(type, info); return(this.getDelegate(obj, index)); }
public void SetValue(object obj, object value) { if (this.setDelegate != null) { this.setDelegate(obj, value); return; } this.setDelegate = DynamicMethodHelper.CreateSetHandler(type, info); this.setDelegate(obj, value); }
private void _Free() { if (_RefTarget != null) { DynamicMethodHelper.FreeReference(_RefTarget.Value); } if (_RefTrampoline != null) { DynamicMethodHelper.FreeReference(_RefTrampoline.Value); } }
public void EmitMethodInvokerInvokeMethodWithoutReturnType() { MathHelper mathHelper = new MathHelper(); MethodInvoker methodInvoker = DynamicMethodHelper.EmitMethodInvoker( typeof(MathHelper), typeof(MathHelper).GetMethod("SetPI", new[] { typeof(double) })); methodInvoker(mathHelper, Math.PI); Assert.AreEqual(Math.PI, mathHelper.PI); }
internal void _UpdateOrig(MethodBase invoke) { if (_OrigDelegateType == null) { return; } Delegate orig = (invoke ?? GenerateTrampoline(_OrigDelegateInvoke)).CreateDelegate(_OrigDelegateType); DynamicMethodHelper.SetReference(_RefTrampoline.Value, orig); DynamicMethodHelper.SetReference(_RefTrampolineTmp.Value, orig); }
public void EmitMethodInvokerInvokeMethodWithReturnTypeAndNoArguments() { MathHelper mathHelper = new MathHelper(); mathHelper.SetPI(Math.PI); object value = DynamicMethodHelper.EmitMethodInvoker( typeof(MathHelper), typeof(MathHelper).GetMethod("GetPI"))(mathHelper); Assert.AreEqual(Math.PI, (double)value); }
public void EmitConstructorInvokerConstructNullableValues() { Assert.AreEqual(default(bool?), DynamicMethodHelper.EmitConstructorInvoker(typeof(bool?))()); Assert.AreEqual(default(byte?), DynamicMethodHelper.EmitConstructorInvoker(typeof(byte?))()); Assert.AreEqual(default(sbyte?), DynamicMethodHelper.EmitConstructorInvoker(typeof(sbyte?))()); Assert.AreEqual(default(short?), DynamicMethodHelper.EmitConstructorInvoker(typeof(short?))()); Assert.AreEqual(default(ushort?), DynamicMethodHelper.EmitConstructorInvoker(typeof(ushort?))()); Assert.AreEqual(default(int?), DynamicMethodHelper.EmitConstructorInvoker(typeof(int?))()); Assert.AreEqual(default(uint?), DynamicMethodHelper.EmitConstructorInvoker(typeof(uint?))()); Assert.AreEqual(default(long?), DynamicMethodHelper.EmitConstructorInvoker(typeof(long?))()); Assert.AreEqual(default(ulong?), DynamicMethodHelper.EmitConstructorInvoker(typeof(ulong?))()); Assert.AreEqual(default(float?), DynamicMethodHelper.EmitConstructorInvoker(typeof(float?))()); Assert.AreEqual(default(decimal?), DynamicMethodHelper.EmitConstructorInvoker(typeof(decimal?))()); Assert.AreEqual(default(DateTime?), DynamicMethodHelper.EmitConstructorInvoker(typeof(DateTime?))()); }
/// <summary> /// Creates a CIL method body from a dynamic method. /// </summary> /// <param name="method">The method that owns the method body.</param> /// <param name="dynamicMethodObj">The Dynamic Method/Delegate/DynamicResolver.</param> /// <param name="operandResolver"> /// The object instance to use for resolving operands of an instruction in the /// method body. /// </param> /// <param name="importer"> /// The object instance to use for importing operands of an instruction in the /// method body. /// </param> /// <returns>The method body.</returns> public static CilMethodBody FromDynamicMethod( MethodDefinition method, object dynamicMethodObj, ICilOperandResolver operandResolver = null, ReferenceImporter importer = null) { if (!(method.Module is SerializedModuleDefinition module)) { throw new ArgumentException("Method body should reference a serialized module."); } var result = new CilMethodBody(method); operandResolver ??= new CilOperandResolver(method.Module, result); importer ??= new ReferenceImporter(method.Module); dynamicMethodObj = DynamicMethodHelper.ResolveDynamicResolver(dynamicMethodObj); //Get Runtime Fields var code = FieldReader.ReadField <byte[]>(dynamicMethodObj, "m_code"); var scope = FieldReader.ReadField <object>(dynamicMethodObj, "m_scope"); var tokenList = FieldReader.ReadField <List <object> >(scope, "m_tokens"); var localSig = FieldReader.ReadField <byte[]>(dynamicMethodObj, "m_localSignature"); var ehHeader = FieldReader.ReadField <byte[]>(dynamicMethodObj, "m_exceptionHeader"); var ehInfos = FieldReader.ReadField <IList <object> >(dynamicMethodObj, "m_exceptions"); // Read raw instructions. var reader = new ByteArrayReader(code); var disassembler = new CilDisassembler(reader); result.Instructions.AddRange(disassembler.ReadAllInstructions()); //Local Variables DynamicMethodHelper.ReadLocalVariables(result, method, localSig); //Exception Handlers DynamicMethodHelper.ReadReflectionExceptionHandlers(result, ehInfos, ehHeader, importer); // Resolve all operands. foreach (var instruction in result.Instructions) { instruction.Operand = DynamicMethodHelper.ResolveOperandReflection(module.ReaderContext, result, instruction, operandResolver, tokenList, importer) ?? instruction.Operand; } return(result); }
public void EmitMethodInvokerInvokeVirtualMethodWithReturnTypeAndNoArguments() { MathHelper mathHelper = new MathHelper(); object value = DynamicMethodHelper.EmitMethodInvoker( typeof(MathHelper), typeof(MathHelper).GetMethod("GetAnInteger"))(mathHelper); Assert.AreEqual(10, (int)value); MathHelperImpl mathHelperImpl = new MathHelperImpl(); value = DynamicMethodHelper.EmitMethodInvoker( typeof(MathHelperImpl), typeof(MathHelperImpl).GetMethod("GetAnInteger"))(mathHelperImpl); Assert.AreEqual(20, (int)value); }
public void EmitConstructorInvokerConstructStructValuesWithParameters() { const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; Type[] parameterTypes = { typeof(int), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int) }; object value = DynamicMethodHelper.EmitConstructorInvoker(typeof(DateTime), typeof(DateTime).GetConstructor(bindingFlags, null, parameterTypes, null), parameterTypes)(2013, 9, 10, 16, 40, 30); Assert.AreEqual(new DateTime(2013, 9, 10, 16, 40, 30), value); parameterTypes = new [] { typeof(int), typeof(int), typeof(int), typeof(int) }; value = DynamicMethodHelper.EmitConstructorInvoker(typeof(Rectangle), typeof(Rectangle).GetConstructor(bindingFlags, null, parameterTypes, null), parameterTypes)(40, 20, 300, 200); Assert.AreEqual(new Rectangle(40, 20, 300, 200), value); parameterTypes = new [] { typeof(int), typeof(int) }; value = DynamicMethodHelper.EmitConstructorInvoker(typeof(Point), typeof(Point).GetConstructor(bindingFlags, null, parameterTypes, null), parameterTypes)(10, 20); Assert.AreEqual(new Point(10, 20), value); }
public static object UnPack(Type type, byte[] datas) { if (addInvoker == null) { var method = type.GetMethod("Add"); addInvoker = DynamicMethodHelper.CreateMethodInvoker(method); } var obj = DynamicMethodHelper.CreateCtorFuncFromCache(type)(); var innerType = type.GenericTypeArguments[0]; int dataIndex = 0; while (dataIndex < datas.Length) { var value = FieldFormat.UnPack(innerType, datas, ref dataIndex); addInvoker.Invoke(obj, new object[] { value }); } return(obj); }
public void EmitConstructorInvokerConstructStructValues() { Assert.AreEqual(default(bool), DynamicMethodHelper.EmitConstructorInvoker(typeof(bool))()); Assert.AreEqual(default(byte), DynamicMethodHelper.EmitConstructorInvoker(typeof(byte))()); Assert.AreEqual(default(sbyte), DynamicMethodHelper.EmitConstructorInvoker(typeof(sbyte))()); Assert.AreEqual(default(short), DynamicMethodHelper.EmitConstructorInvoker(typeof(short))()); Assert.AreEqual(default(ushort), DynamicMethodHelper.EmitConstructorInvoker(typeof(ushort))()); Assert.AreEqual(default(int), DynamicMethodHelper.EmitConstructorInvoker(typeof(int))()); Assert.AreEqual(default(uint), DynamicMethodHelper.EmitConstructorInvoker(typeof(uint))()); Assert.AreEqual(default(long), DynamicMethodHelper.EmitConstructorInvoker(typeof(long))()); Assert.AreEqual(default(ulong), DynamicMethodHelper.EmitConstructorInvoker(typeof(ulong))()); Assert.AreEqual(default(float), DynamicMethodHelper.EmitConstructorInvoker(typeof(float))()); Assert.AreEqual(default(decimal), DynamicMethodHelper.EmitConstructorInvoker(typeof(decimal))()); Assert.AreEqual(default(Rectangle), DynamicMethodHelper.EmitConstructorInvoker(typeof(Rectangle))()); Assert.AreEqual(default(Point), DynamicMethodHelper.EmitConstructorInvoker(typeof(Point))()); Assert.AreEqual(default(Color), DynamicMethodHelper.EmitConstructorInvoker(typeof(Color))()); Assert.AreEqual(default(DateTime), DynamicMethodHelper.EmitConstructorInvoker(typeof(DateTime))()); }
//static Dictionary<Type, TypeInfo> TypeInfoCache = new Dictionary<Type, TypeInfo>(); //static TypeInfo getTypeInfo(Type type) //{ // var a = TypeInfoCache.TryGetValue(type, out TypeInfo typeInfo); // if (!a) // { // var typeRef = typeof(ReflectionHelper); // var method = typeRef.GetMethod(nameof(ReflectionHelper.GetInfo), BindingFlags.Public | BindingFlags.Static); // var refInfo = method.MakeGenericMethod(new Type[] { type }).Invoke(null, new object[] { null }) as IReflectionInfo; // var pro = type.GetProperties().Where(b => b.GetSetMethod() != null); // typeInfo = new TypeInfo() { Properties = pro, ReflectionInfo = refInfo }; // TypeInfoCache.Add(type, typeInfo); // } // return typeInfo; //} public static object UnPack(Type type, byte[] datas) { var obj = DynamicMethodHelper.CreateCtorFuncFromCache(type)(); var typeInfo = type.GetReflectionInfo(); int dataIndex = 0; foreach (var p in typeInfo.Properties) { var value = FieldFormat.UnPack(p.PropertyType, datas, ref dataIndex); if (value == null) { continue; } typeInfo.ReflectionInfo.SetValue(obj, p.Name, value); //p.SetValue(obj, value); } return(obj); }
public static serviceInfo GetServiceInfo(Type type, bool initObjCtor = false) { var a = serviceInfoCache.TryGetValue(type, out var info); if (a) { return(info); } info = new serviceInfo() { ServiceType = type, Attributes = type.GetCustomAttributes().ToList(), }; if (initObjCtor) { info.InstaceCtor = DynamicMethodHelper.CreateCtorFunc <Func <object> >(type, Type.EmptyTypes); } var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance); var methodInfoList = new List <methodInfo>(); foreach (var m in methods) { var mInfo = new methodInfo() { Attributes = m.GetCustomAttributes().ToList(), MethodInfo = m, Parameters = m.GetParameters(), MethodInvoker = DynamicMethodHelper.CreateMethodInvoker(m) }; mInfo.IsAsync = m.ReturnType.Name.StartsWith("Task`1"); if (mInfo.IsAsync) //总是返回同步结果 { mInfo.TaskInvoker = DynamicMethodHelper.TaskResultInvoker <object>(m.ReturnType); var taskType = typeof(AsyncResult <>).MakeGenericType(m.ReturnType.GetGenericArguments()[0]); mInfo.TaskCreater = DynamicMethodHelper.CreateCtorFunc <Func <AsyncResult> >(taskType, new Type[0]); } methodInfoList.Add(mInfo); } info.Methods = methodInfoList; info.ServiceAttribute = type.GetCustomAttribute <ServiceAttribute>() ?? new ServiceAttribute(); apiPrefixCache.TryAdd(info.ServiceAttribute.ApiPrefix, type); serviceInfoCache.TryAdd(type, info); return(info); }
public static object UnPack(Type type, byte[] datas) { var dic = (System.Collections.IDictionary)DynamicMethodHelper.CreateCtorFuncFromCache(type)(); var allArgs = type.GenericTypeArguments; var innerType = allArgs[0]; var innerType2 = allArgs[1]; int dataIndex = 0; while (dataIndex < datas.Length) { var key = FieldFormat.UnPack(innerType, datas, ref dataIndex); var value = FieldFormat.UnPack(innerType2, datas, ref dataIndex); if (key == null) { continue; } dic.Add(key, value); } return(dic); }
private static void RunConstructorBenchmark() { ConstructorInfo constructorInfo = typeof(Person).GetConstructor( BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[0], null); ConstructorInvoker constructorInvoker = DynamicMethodHelper.EmitConstructorInvoker(typeof(Person)); object[] emptyParameters = new object[0]; Dictionary <string, Action> actions = new Dictionary <string, Action> { { "Direct ctor", () => new Person() }, { "Reflection ctor", () => constructorInfo.Invoke(emptyParameters) }, { "Labo ctor", () => ReflectionHelper.CreateInstance(typeof(Person), constructorInfo, Type.EmptyTypes) }, { "Labo cached ctor", () => constructorInvoker() }, }; Execute("Benchmark for Object Construction", actions); }
public void EmitConstructorInvokerInvokeParameterlessConstructor() { Type personType = typeof(Person); Type[] parameterTypes = { }; ConstructorInvoker constructorInvoker = DynamicMethodHelper.EmitConstructorInvoker( personType, personType.GetConstructor( BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, parameterTypes, null), parameterTypes); Person person = (Person)constructorInvoker(); Assert.IsNotNull(person); Assert.AreEqual(Person.DEFAULT_NAME, person.Name); Assert.AreEqual(Person.DEFAULT_SURNAME, person.Surname); Assert.AreEqual(Person.DEFAULT_AGE, person.Age); }
/// <summary> /// 扫码程序集,注册事件处理程序 /// </summary> /// <param name="assembly"></param> public void ScanEventHandler(Assembly assembly) { foreach (var type in assembly.GetTypes()) { var methodInfos = type.GetMethods(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic ^ BindingFlags.GetProperty ^ BindingFlags.SetProperty); foreach (var methodInfo in methodInfos) { var mehAttr = methodInfo.GetCustomAttribute <AppEventHandlerAttribute>(); if (mehAttr == null) { continue; } var fun = DynamicMethodHelper.GetExecuteDelegate(methodInfo); AddHandler(mehAttr.EventKey, (args) => fun(methodInfo.IsStatic ? null : Activator.CreateInstance(type), args)); } } }
/// <summary> /// 扫描容器中的服务,注册时间处理程序 /// </summary> /// <param name="services"></param> public void ScanEventHandler(IServiceCollection services) { foreach (var service in services) { var methodInfos = service.ServiceType.GetMethods( BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic ^ BindingFlags.GetProperty ^ BindingFlags.SetProperty); foreach (var methodInfo in methodInfos) { var mehAttr = methodInfo.GetCustomAttribute <AppEventHandlerAttribute>(); if (mehAttr == null) { continue; } var fun = DynamicMethodHelper.GetExecuteDelegate(methodInfo); AddHandler(mehAttr.EventKey, (args) => fun(methodInfo.IsStatic ? null : _serviceProvider.GetService(service.ServiceType), args)); } } }
private static void RunMethodBenchmark() { MethodInfo methodInfo = typeof(Person).GetMethod("GetName", BindingFlags.Instance | BindingFlags.NonPublic, null, Type.EmptyTypes, null); MethodInvoker methodInvoker = DynamicMethodHelper.EmitMethodInvoker(typeof(Person), methodInfo); object[] emptyParameters = new object[0]; Dictionary <string, Action> actions = new Dictionary <string, Action> { { "Direct method", () => new Person().GetName() }, { "Reflection method", () => methodInfo.Invoke(new Person(), emptyParameters) }, { "dynamic method", () => { dynamic person = new Person(); string name = person.GetName(); } }, { "Labo expression method", () => ExpressionHelper.CallMethod(new Person(), methodInfo) }, { "Labo method", () => ReflectionHelper.CallMethod(new Person(), methodInfo) }, { "Labo cached method", () => methodInvoker(new Person()) }, }; Execute("Benchmark for Method Invocation", actions); }
bool SubscribeData(object args) { var ed = args as EventDeclare; var name = $"CRL_QUEUE_{ed.Name}"; var coll = database.GetCollection <MongoData>(name); var list = coll.Find(b => true).SortBy(b => b.Time).Limit(ed.ListTake).ToList(); if (list.Count == 0) { return(true); } if (ed.IsArray) { var objInstance = DynamicMethodHelper.CreateCtorFuncFromCache(ed.EventDataType)(); var innerType = ed.EventDataType.GenericTypeArguments[0]; var method = ed.EventDataType.GetMethod("Add"); foreach (var m in list) { var item = m.Data.ToObject(innerType); method.Invoke(objInstance, new object[] { item }); } ed.MethodInvoke.Invoke(ed.CreateServiceInstance(), new object[] { objInstance }); var ids = list.Select(b => b.Id).ToArray(); coll.DeleteMany(b => ids.Contains(b.Id)); } else { foreach (var m in list) { var item = m.Data.ToObject(ed.EventDataType); ed.MethodInvoke.Invoke(ed.CreateServiceInstance(), new object[] { item }); coll.DeleteOne(b => b.Id == m.Id); } } return(true); }
public object Execute(ParameterList parameters, FunctionContextContainer context) { try { var dynamicMethod = DynamicMethodHelper.GetDynamicMethod("<C1 function> " + _functionToWrap.CompositeName()); return(dynamicMethod(() => _functionToWrap.Execute(parameters, context))); } catch (Exception ex) { if (_functionToWrap.ReturnType == typeof(XhtmlDocument) || (_functionToWrap.ReturnType == typeof(void) && ex is HttpCompileException)) { XElement errorBoxHtml; if (context.ProcessException(_functionToWrap.CompositeName(), ex, LogTitle, out errorBoxHtml)) { XhtmlDocument errorInfoDocument = new XhtmlDocument(); errorInfoDocument.Body.Add(errorBoxHtml); return(errorInfoDocument); } } throw; } }
static void GenerateCompareTypeIL(DynamicMethodHelper il, Type t) { MethodInfo method = GetTypeMethod(t, TypeMethodType.Compare); if ((method == null) && (t.IsPrimitive == false)) { il.Pop(); il.Pop(); il.PushInt(1); return; } il.BeginScope(); { const string valX = "x"; const string valY = "y"; const string valThis = "_thisX"; const string trueLabel = "endTrue"; const string falseLabel = "endFalse"; const string endLabel = "endCheck"; il.DeclareLocal(valX, typeof(object)); il.PopLocal(valX); il.DeclareLocal(valY, typeof(object)); il.PopLocal(valY); // If both null or the same object then return true il.PushLocal(valX); il.PushLocal(valY); il.GotoIfEqual(trueLabel); // Exit false if either value is null il.PushLocal(valX); il.GotoIfFalse(falseLabel); il.PushLocal(valY); il.GotoIfFalse(falseLabel); // Both operands are non-null so call the type-specific comparison method if (t.IsPrimitive) { il.PushLocal(valX); il.UnboxValueType(t); il.PushLocal(valX); il.UnboxValueType(t); il.CompareEqual(); } else { Type paramType = method.GetParameters()[0].ParameterType; il.DebugWriteLine("Calling " + method); if (method.IsStatic) { il.PushLocal(valX); if (paramType.IsValueType) il.UnboxValueType(paramType); } else { il.DeclareLocal(valThis, t); il.PushLocal(valX); il.PopLocalFromObject(valThis); il.PushThis(valThis, method); } il.PushLocal(valY); if (paramType.IsValueType) il.UnboxValueType(paramType); il.CallMethod(method); } il.GotoIfFalse(falseLabel); il.MarkLabel(trueLabel); il.PushInt(1); il.Goto(endLabel); il.MarkLabel(falseLabel); il.DebugWriteLine("The following values are not equal:"); il.DebugWriteLocal(valX); il.DebugWriteLocal(valY); il.PushInt(0); il.MarkLabel(endLabel); } il.EndScope(); }
public void GenerateCompareIL(DynamicMethodHelper il, int xIndex, int yIndex) { #region Names const string instanceX = "instanceX"; const string propVarX = "propValueX"; const string enumerableX = "enumerableX"; const string enumVarX = "enumX"; const string dictEnumVarX = "dictEnumX"; const string instanceY = "instanceY"; const string propVarY = "propValueY"; const string enumerableY = "enumerableY"; const string enumVarY = "enumY"; const string dictEnumVarY = "dictEnumY"; const string endFalseLabel = "logBadPropertyLabel"; const string endTrueLabel = "endTrue"; const string endLabel = "endLabel"; const string loopStart = "loopStart"; const string loopEnd = "loopEnd"; #endregion il.DebugWriteLine("Comparing property " + this.Name); il.DeclareLocal(instanceX, this.OwnerType); il.PushArg(xIndex); il.PopLocal(instanceX); il.DeclareLocal(instanceY, this.OwnerType); il.PushArg(yIndex); il.PopLocal(instanceY); il.DeclareLocal(propVarX, this.Type); il.DeclareLocal(propVarY, this.Type); if (this.classType != null) { il.CopyLocal(instanceX, propVarX); il.CopyLocal(instanceY, propVarY); } else if (this.property is PropertyInfo) { PropertyInfo pi = (PropertyInfo)this.property; MethodInfo getMethod = pi.GetGetMethod(true); il.CallMethod(instanceX, getMethod); il.PopLocal(propVarX); il.CallMethod(instanceY, getMethod); il.PopLocal(propVarY); } else { il.GetField(instanceX, this.property as FieldInfo); il.PopLocal(propVarX); il.GetField(instanceY, this.property as FieldInfo); il.PopLocal(propVarY); } // For ref types, if both null or the same object then return true // For value types, this is a value comparison Type t = IsCollection ? (IsDictionary ? null : this.elementType) : this.Type; bool doDefault = true; if (t != null && t.IsValueType) { MethodInfo mi = t.GetMethod("op_Equality", new [] { t, t }); if (mi != null) { il.PushLocal(propVarX); il.PushLocal(propVarY); il.CallMethod(mi); il.GotoIfFalse(endTrueLabel); doDefault = false; } else if (t.IsGenericType && t.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) { Type it = t.GetGenericArguments()[0]; mi = typeof(Nullable).GetMethod("Equals", BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly); mi = mi.MakeGenericMethod(it); il.PushLocal(propVarX); il.PushLocal(propVarY); il.CallMethod(mi); il.GotoIfFalse(endTrueLabel); doDefault = false; } } if (doDefault) { il.PushLocal(propVarX); il.PushLocal(propVarY); il.GotoIfEqual(endTrueLabel); } if (IsCollection) { il.DeclareLocal(enumerableX, typeof(IEnumerable)); il.DeclareLocal(enumVarX, typeof(IEnumerator)); il.DeclareLocal(enumerableY, typeof(IEnumerable)); il.DeclareLocal(enumVarY, typeof(IEnumerator)); il.CopyLocal(propVarX, enumerableX); il.CallMethod(enumerableX, "GetEnumerator"); il.PopLocal(enumVarX); il.CopyLocal(propVarY, enumerableX); il.CallMethod(enumerableX, "GetEnumerator"); il.PopLocal(enumVarY); if (IsDictionary) { il.DeclareLocal(dictEnumVarX, typeof(IDictionaryEnumerator)); il.CopyLocal(enumVarX, dictEnumVarX); il.DeclareLocal(dictEnumVarY, typeof(IDictionaryEnumerator)); il.CopyLocal(enumVarY, dictEnumVarY); } il.MarkLabel(loopStart); il.CallMethod(enumVarX, "MoveNext"); il.GotoIfFalse(loopEnd); il.CallMethod(enumVarY, "MoveNext"); il.GotoIfFalse(endFalseLabel); // y has less elements than x if (IsDictionary) { il.CallMethod(dictEnumVarX, "get_Key"); il.CallMethod(dictEnumVarY, "get_Key"); GenerateCompareTypeIL(il, this.dictionaryKeyType); il.GotoIfFalse(endFalseLabel); il.CallMethod(dictEnumVarX, "get_Value"); il.CallMethod(dictEnumVarY, "get_Value"); GenerateCompareTypeIL(il, this.dictionaryValueType); il.GotoIfFalse(endFalseLabel); } else // if (not dictionary) { il.CallMethod(enumVarX, "get_Current"); il.CallMethod(enumVarY, "get_Current"); GenerateCompareTypeIL(il, this.elementType); il.GotoIfFalse(endFalseLabel); } il.Goto(loopStart); il.MarkLabel(loopEnd); // enumVarX has no more elements so enumVarY shouldn't // have any more either il.CallMethod(enumVarY, "MoveNext"); il.GotoIfTrue(endFalseLabel); // count mismatch } else // if (not collection) { il.PushLocalAsObject(propVarX); il.PushLocalAsObject(propVarY); GenerateCompareTypeIL(il, this.Type); il.GotoIfFalse(endFalseLabel); } il.MarkLabel(endTrueLabel); //il.DebugWriteLine(string.Format("Property {0} is equal", this.Name)); il.PushInt(1); il.Goto(endLabel); // Log out name of property if not equal il.MarkLabel(endFalseLabel); il.DebugWriteLine(string.Format("Property {0} is not equal", this.Name)); il.PushInt(0); // set success to false il.MarkLabel(endLabel); }
public Hook(MethodBase from, MethodInfo to, object target) { Method = from; _Hook = to; if (_Hook.ReturnType != ((from as MethodInfo)?.ReturnType ?? typeof(void))) { throw new InvalidOperationException($"Return type of hook for {from} doesn't match, must be {((from as MethodInfo)?.ReturnType ?? typeof(void)).FullName}"); } if (target == null && !to.IsStatic) { throw new InvalidOperationException($"Hook for method {from} must be static, or you must pass a target instance."); } ParameterInfo[] hookArgs = _Hook.GetParameters(); // Check if the parameters match. // If the delegate has got an extra first parameter that itself is a delegate, it's the orig trampoline passthrough. ParameterInfo[] args = Method.GetParameters(); Type[] argTypes; if (!Method.IsStatic) { argTypes = new Type[args.Length + 1]; argTypes[0] = Method.DeclaringType; for (int i = 0; i < args.Length; i++) { argTypes[i + 1] = args[i].ParameterType; } } else { argTypes = new Type[args.Length]; for (int i = 0; i < args.Length; i++) { argTypes[i] = args[i].ParameterType; } } Type origType = null; if (hookArgs.Length == argTypes.Length + 1 && typeof(Delegate).IsAssignableFrom(hookArgs[0].ParameterType)) { origType = hookArgs[0].ParameterType; } else if (hookArgs.Length != argTypes.Length) { throw new InvalidOperationException($"Parameter count of hook for {from} doesn't match, must be {argTypes.Length}"); } for (int i = 0; i < argTypes.Length; i++) { Type argMethod = argTypes[i]; Type argHook = hookArgs[i + (origType == null ? 0 : 1)].ParameterType; if (!argMethod.IsAssignableFrom(argHook) && !argHook.IsAssignableFrom(argMethod)) { throw new InvalidOperationException($"Parameter #{i} of hook for {from} doesn't match, must be {argMethod.FullName} or related"); } } MethodInfo origInvoke = origType?.GetMethod("Invoke"); // TODO: Check origType Invoke arguments. DynamicMethod dm; ILGenerator il; dm = new DynamicMethod( $"hook_{Method.Name}_{GetHashCode()}", (Method as MethodInfo)?.ReturnType ?? typeof(void), argTypes, Method.DeclaringType, true ); il = dm.GetILGenerator(); if (target != null) { _RefTarget = il.EmitReference(target); } if (origType != null) { _RefTrampoline = il.EmitReference <Delegate>(null); } // TODO: Use specialized Ldarg.* if possible; What about ref types? for (int i = 0; i < argTypes.Length; i++) { il.Emit(OpCodes.Ldarg, i); } il.Emit(OpCodes.Call, _Hook); il.Emit(OpCodes.Ret); Target = dm.Pin(); _Detour = new Detour(Method, Target); if (origType != null) { DynamicMethodHelper.SetReference(_RefTrampoline.Value, GenerateTrampoline(origInvoke).CreateDelegate(origType)); } }
public MethodInvoker Create() { #if DIAGNOSTICS Cef.Logger.Trace(LogTarget.ScriptableObject, "Creating method [{0}]", GetMethodInvokerName(this.def)); #endif // Passing method arguments by ref is not supported. if (this.def.GetMethods().Any(_ => _.GetParameters().Any(p => p.ParameterType.IsByRef))) { throw new JSBindingException("Passing method arguments by ref is not supported."); } // Mixing static and instance methods are not supported. if (this.def.GetMethods().All(_ => _.IsStatic) == this.def.GetMethods().All(_ => !_.IsStatic) ) { throw new JSBindingException("Mixing static and instance methods are not supported."); } var methodInvoker = typeof(MethodInvoker).GetMethod("Invoke"); var emit = new DynamicMethodHelper( GetMethodInvokerName(def), methodInvoker.ReturnType, methodInvoker.GetParameters().Select(_ => _.ParameterType).ToArray() ) .Emitter; if (!this.def.HasOverloads && this.def.GetMethods().Single().GetParameters().All(_ => !_.IsOptional)) { EmitInvoker(emit, this.def.GetMethods().Single(), null, this.def.Setter ); } else { var methods = this.def.GetMethods() .GroupBy(_ => _.GetParameters().Length, _ => _) .ToDictionary(_ => _.Key, _ => _.ToList()) ; // expand methods with optional arguments var methodsWithOptArgs = this.def.GetMethods().Where(_ => _.GetParameters().Any(p => p.IsOptional)); foreach (var m in methodsWithOptArgs) { // if full method signature already placed in methods dictionary var parameters = m.GetParameters(); for (var k = parameters.Length - 1; k >= 0; k--) { if (!parameters[k].IsOptional) break; if (!methods.ContainsKey(k)) methods.Add(k, new List<MethodInfo>()); // check, that if methods already includes this signature, then doesn't expand if (!methods[k].Any(_ => { var p0 = _.GetParameters(); for (var i = 0; i < k; i++) { if (parameters[i].ParameterType != p0[i].ParameterType) return false; } return true; })) { methods[k].Add(m); } } } // type variance handling foreach (var k in methods.Keys) { var mlist = methods[k]; if (mlist.Count > 1) // if methods for argc==k has overloads { // detect arguments which have type variance List<int> vargs = new List<int>(); for (int i = 0; i < k; i++) { if (mlist.Select(_ => _.GetParameters()[i].ParameterType).Distinct().Count() != 1) { vargs.Add(i); } } // TODO: hide methods which not reacheable by type priority (int hides short or byte) // stub, throw exception for currently unsupported if (vargs.Count > 0) { throw new JSBindingException( string.Format("Overloading by argument type variance currently is not supported. name=[{0}], argc=[{1}], vargs=[{2}]", this.def.Name, k, string.Join(", ", vargs) ) ); } } } var defaultLabel = emit.DefineLabel(); var labels = new Label[methods.Keys.Max() + 1]; for (var i = 0; i < labels.Length; i++) { if (methods.ContainsKey(i)) { labels[i] = emit.DefineLabel(); } else { labels[i] = defaultLabel; } } emit.LdArg(argumentsCountArgIndex) .Switch(labels) ; emit.MarkLabel(defaultLabel) .Call(throwArgumentCountMismatchMethod) ; // write labels for (var i = 0; i < labels.Length; i++) { if (labels[i] == defaultLabel) continue; emit.MarkLabel(labels[i]); EmitInvoker(emit, methods[i].Single(), i, false ); } // TODO: check, optimize type variance or throw if not supported } return (MethodInvoker)emit.DynamicMethod.CreateDelegate(typeof(MethodInvoker)); }