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