1 #region License 2 // Copyright (c) 2007 James Newton-King 3 // 4 // Permission is hereby granted, free of charge, to any person 5 // obtaining a copy of this software and associated documentation 6 // files (the "Software"), to deal in the Software without 7 // restriction, including without limitation the rights to use, 8 // copy, modify, merge, publish, distribute, sublicense, and/or sell 9 // copies of the Software, and to permit persons to whom the 10 // Software is furnished to do so, subject to the following 11 // conditions: 12 // 13 // The above copyright notice and this permission notice shall be 14 // included in all copies or substantial portions of the Software. 15 // 16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 // OTHER DEALINGS IN THE SOFTWARE. 24 #endregion 25 26 #if !(SILVERLIGHT || PORTABLE || NETFX_CORE) 27 using System; 28 using System.Collections.Generic; 29 #if NET20 30 using Newtonsoft.Json.Utilities.LinqBridge; 31 #endif 32 using System.Reflection; 33 using System.Reflection.Emit; 34 using Newtonsoft.Json.Serialization; 35 using System.Globalization; 36 37 namespace Newtonsoft.Json.Utilities 38 { 39 internal class DynamicReflectionDelegateFactory : ReflectionDelegateFactory 40 { 41 public static DynamicReflectionDelegateFactory Instance = new DynamicReflectionDelegateFactory(); 42 CreateDynamicMethod(string name, Type returnType, Type[] parameterTypes, Type owner)43 private static DynamicMethod CreateDynamicMethod(string name, Type returnType, Type[] parameterTypes, Type owner) 44 { 45 DynamicMethod dynamicMethod = !owner.IsInterface() 46 ? new DynamicMethod(name, returnType, parameterTypes, owner, true) 47 : new DynamicMethod(name, returnType, parameterTypes, owner.Module, true); 48 49 return dynamicMethod; 50 } 51 CreateMethodCall(MethodBase method)52 public override MethodCall<T, object> CreateMethodCall<T>(MethodBase method) 53 { 54 DynamicMethod dynamicMethod = CreateDynamicMethod(method.ToString(), typeof(object), new[] { typeof(object), typeof(object[]) }, method.DeclaringType); 55 ILGenerator generator = dynamicMethod.GetILGenerator(); 56 57 GenerateCreateMethodCallIL(method, generator); 58 59 return (MethodCall<T, object>)dynamicMethod.CreateDelegate(typeof(MethodCall<T, object>)); 60 } 61 GenerateCreateMethodCallIL(MethodBase method, ILGenerator generator)62 private void GenerateCreateMethodCallIL(MethodBase method, ILGenerator generator) 63 { 64 ParameterInfo[] args = method.GetParameters(); 65 66 Label argsOk = generator.DefineLabel(); 67 68 generator.Emit(OpCodes.Ldarg_1); 69 generator.Emit(OpCodes.Ldlen); 70 generator.Emit(OpCodes.Ldc_I4, args.Length); 71 generator.Emit(OpCodes.Beq, argsOk); 72 73 generator.Emit(OpCodes.Newobj, typeof(TargetParameterCountException).GetConstructor(ReflectionUtils.EmptyTypes)); 74 generator.Emit(OpCodes.Throw); 75 76 generator.MarkLabel(argsOk); 77 78 if (!method.IsConstructor && !method.IsStatic) 79 generator.PushInstance(method.DeclaringType); 80 81 for (int i = 0; i < args.Length; i++) 82 { 83 generator.Emit(OpCodes.Ldarg_1); 84 generator.Emit(OpCodes.Ldc_I4, i); 85 generator.Emit(OpCodes.Ldelem_Ref); 86 87 generator.UnboxIfNeeded(args[i].ParameterType); 88 } 89 90 if (method.IsConstructor) 91 generator.Emit(OpCodes.Newobj, (ConstructorInfo)method); 92 else if (method.IsFinal || !method.IsVirtual) 93 generator.CallMethod((MethodInfo)method); 94 95 Type returnType = method.IsConstructor 96 ? method.DeclaringType 97 : ((MethodInfo)method).ReturnType; 98 99 if (returnType != typeof(void)) 100 generator.BoxIfNeeded(returnType); 101 else 102 generator.Emit(OpCodes.Ldnull); 103 104 generator.Return(); 105 } 106 CreateDefaultConstructor(Type type)107 public override Func<T> CreateDefaultConstructor<T>(Type type) 108 { 109 DynamicMethod dynamicMethod = CreateDynamicMethod("Create" + type.FullName, typeof(T), ReflectionUtils.EmptyTypes, type); 110 dynamicMethod.InitLocals = true; 111 ILGenerator generator = dynamicMethod.GetILGenerator(); 112 113 GenerateCreateDefaultConstructorIL(type, generator); 114 115 return (Func<T>)dynamicMethod.CreateDelegate(typeof(Func<T>)); 116 } 117 GenerateCreateDefaultConstructorIL(Type type, ILGenerator generator)118 private void GenerateCreateDefaultConstructorIL(Type type, ILGenerator generator) 119 { 120 if (type.IsValueType()) 121 { 122 generator.DeclareLocal(type); 123 generator.Emit(OpCodes.Ldloc_0); 124 generator.Emit(OpCodes.Box, type); 125 } 126 else 127 { 128 ConstructorInfo constructorInfo = 129 type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, 130 ReflectionUtils.EmptyTypes, null); 131 132 if (constructorInfo == null) 133 throw new ArgumentException("Could not get constructor for {0}.".FormatWith(CultureInfo.InvariantCulture, type)); 134 135 generator.Emit(OpCodes.Newobj, constructorInfo); 136 } 137 138 generator.Return(); 139 } 140 CreateGet(PropertyInfo propertyInfo)141 public override Func<T, object> CreateGet<T>(PropertyInfo propertyInfo) 142 { 143 DynamicMethod dynamicMethod = CreateDynamicMethod("Get" + propertyInfo.Name, typeof(T), new[] { typeof(object) }, propertyInfo.DeclaringType); 144 ILGenerator generator = dynamicMethod.GetILGenerator(); 145 146 GenerateCreateGetPropertyIL(propertyInfo, generator); 147 148 return (Func<T, object>)dynamicMethod.CreateDelegate(typeof(Func<T, object>)); 149 } 150 GenerateCreateGetPropertyIL(PropertyInfo propertyInfo, ILGenerator generator)151 private void GenerateCreateGetPropertyIL(PropertyInfo propertyInfo, ILGenerator generator) 152 { 153 MethodInfo getMethod = propertyInfo.GetGetMethod(true); 154 if (getMethod == null) 155 throw new ArgumentException("Property '{0}' does not have a getter.".FormatWith(CultureInfo.InvariantCulture, propertyInfo.Name)); 156 157 if (!getMethod.IsStatic) 158 generator.PushInstance(propertyInfo.DeclaringType); 159 160 generator.CallMethod(getMethod); 161 generator.BoxIfNeeded(propertyInfo.PropertyType); 162 generator.Return(); 163 } 164 CreateGet(FieldInfo fieldInfo)165 public override Func<T, object> CreateGet<T>(FieldInfo fieldInfo) 166 { 167 DynamicMethod dynamicMethod = CreateDynamicMethod("Get" + fieldInfo.Name, typeof(T), new[] { typeof(object) }, fieldInfo.DeclaringType); 168 ILGenerator generator = dynamicMethod.GetILGenerator(); 169 170 GenerateCreateGetFieldIL(fieldInfo, generator); 171 172 return (Func<T, object>)dynamicMethod.CreateDelegate(typeof(Func<T, object>)); 173 } 174 GenerateCreateGetFieldIL(FieldInfo fieldInfo, ILGenerator generator)175 private void GenerateCreateGetFieldIL(FieldInfo fieldInfo, ILGenerator generator) 176 { 177 if (!fieldInfo.IsStatic) 178 generator.PushInstance(fieldInfo.DeclaringType); 179 180 generator.Emit(OpCodes.Ldfld, fieldInfo); 181 generator.BoxIfNeeded(fieldInfo.FieldType); 182 generator.Return(); 183 } 184 CreateSet(FieldInfo fieldInfo)185 public override Action<T, object> CreateSet<T>(FieldInfo fieldInfo) 186 { 187 DynamicMethod dynamicMethod = CreateDynamicMethod("Set" + fieldInfo.Name, null, new[] { typeof(T), typeof(object) }, fieldInfo.DeclaringType); 188 ILGenerator generator = dynamicMethod.GetILGenerator(); 189 190 GenerateCreateSetFieldIL(fieldInfo, generator); 191 192 return (Action<T, object>)dynamicMethod.CreateDelegate(typeof(Action<T, object>)); 193 } 194 GenerateCreateSetFieldIL(FieldInfo fieldInfo, ILGenerator generator)195 internal static void GenerateCreateSetFieldIL(FieldInfo fieldInfo, ILGenerator generator) 196 { 197 if (!fieldInfo.IsStatic) 198 generator.PushInstance(fieldInfo.DeclaringType); 199 200 generator.Emit(OpCodes.Ldarg_1); 201 generator.UnboxIfNeeded(fieldInfo.FieldType); 202 generator.Emit(OpCodes.Stfld, fieldInfo); 203 generator.Return(); 204 } 205 CreateSet(PropertyInfo propertyInfo)206 public override Action<T, object> CreateSet<T>(PropertyInfo propertyInfo) 207 { 208 DynamicMethod dynamicMethod = CreateDynamicMethod("Set" + propertyInfo.Name, null, new[] { typeof(T), typeof(object) }, propertyInfo.DeclaringType); 209 ILGenerator generator = dynamicMethod.GetILGenerator(); 210 211 GenerateCreateSetPropertyIL(propertyInfo, generator); 212 213 return (Action<T, object>)dynamicMethod.CreateDelegate(typeof(Action<T, object>)); 214 } 215 GenerateCreateSetPropertyIL(PropertyInfo propertyInfo, ILGenerator generator)216 internal static void GenerateCreateSetPropertyIL(PropertyInfo propertyInfo, ILGenerator generator) 217 { 218 MethodInfo setMethod = propertyInfo.GetSetMethod(true); 219 if (!setMethod.IsStatic) 220 generator.PushInstance(propertyInfo.DeclaringType); 221 222 generator.Emit(OpCodes.Ldarg_1); 223 generator.UnboxIfNeeded(propertyInfo.PropertyType); 224 generator.CallMethod(setMethod); 225 generator.Return(); 226 } 227 } 228 } 229 #endif