2 // Permission is hereby granted, free of charge, to any person obtaining
3 // a copy of this software and associated documentation files (the
4 // "Software"), to deal in the Software without restriction, including
5 // without limitation the rights to use, copy, modify, merge, publish,
6 // distribute, sublicense, and/or sell copies of the Software, and to
7 // permit persons to whom the Software is furnished to do so, subject to
8 // the following conditions:
10 // The above copyright notice and this permission notice shall be
11 // included in all copies or substantial portions of the Software.
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
15 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
17 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
18 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
19 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 // Copyright (C) Lluis Sanchez Gual, 2004
26 using System.Collections;
27 using System.Reflection.Emit;
28 using System.Reflection;
30 namespace Mono.CodeGeneration
32 public class CodeGenerationHelper
34 public static void GenerateMethodCall (ILGenerator gen, CodeExpression target, MethodBase method, params CodeExpression[] parameters)
36 Type[] ptypes = Type.EmptyTypes;
37 // It could raise an error since GetParameters() on MethodBuilder is not supported.
38 if (parameters.Length > 0) {
39 ParameterInfo[] pars = method.GetParameters ();
40 ptypes = new Type[pars.Length];
41 for (int n=0; n<ptypes.Length; n++) ptypes[n] = pars[n].ParameterType;
43 GenerateMethodCall (gen, target, method, ptypes, parameters);
46 public static void GenerateMethodCall (ILGenerator gen, CodeExpression target, CodeMethod method, params CodeExpression[] parameters)
48 GenerateMethodCall (gen, target, method.MethodBase, method.ParameterTypes, parameters);
51 static void GenerateMethodCall (ILGenerator gen, CodeExpression target, MethodBase method, Type[] parameterTypes, params CodeExpression[] parameters)
55 if (parameterTypes.Length != parameters.Length)
56 throw GetMethodException (method, "Invalid number of parameters, expected " + parameterTypes.Length + ", found " + parameters.Length + ".");
58 if (!object.ReferenceEquals (target, null))
60 target.Generate (gen);
62 Type targetType = target.GetResultType();
63 if (targetType.IsValueType) {
64 LocalBuilder lb = gen.DeclareLocal (targetType);
65 gen.Emit (OpCodes.Stloc, lb);
66 gen.Emit (OpCodes.Ldloca, lb);
67 callOp = OpCodes.Call;
70 callOp = OpCodes.Callvirt;
73 callOp = OpCodes.Call;
75 for (int n=0; n<parameterTypes.Length; n++) {
77 CodeExpression par = parameters[n];
79 GenerateSafeConversion (gen, parameterTypes[n], par.GetResultType());
81 catch (InvalidOperationException ex) {
82 throw GetMethodException (method, "Parameter " + n + ". " + ex.Message);
86 if (method is MethodInfo)
87 gen.Emit (callOp, (MethodInfo)method);
88 else if (method is ConstructorInfo)
89 gen.Emit (callOp, (ConstructorInfo)method);
92 public static Exception GetMethodException (MethodBase method, string msg)
94 return new InvalidOperationException ("Call to method " + method.DeclaringType + "." + method.Name + ": " + msg);
97 public static void GenerateSafeConversion (ILGenerator gen, Type targetType, Type sourceType)
99 if (!targetType.IsAssignableFrom (sourceType)) {
100 throw new InvalidOperationException ("Invalid type conversion. Found '" + sourceType + "', expected '" + targetType + "'.");
103 if (targetType == typeof(object) && sourceType.IsValueType) {
104 gen.Emit (OpCodes.Box, sourceType);
108 public static void LoadFromPtr (ILGenerator ig, Type t)
110 if (t == typeof(int))
111 ig.Emit (OpCodes.Ldind_I4);
112 else if (t == typeof(uint))
113 ig.Emit (OpCodes.Ldind_U4);
114 else if (t == typeof(short))
115 ig.Emit (OpCodes.Ldind_I2);
116 else if (t == typeof(ushort))
117 ig.Emit (OpCodes.Ldind_U2);
118 else if (t == typeof(char))
119 ig.Emit (OpCodes.Ldind_U2);
120 else if (t == typeof(byte))
121 ig.Emit (OpCodes.Ldind_U1);
122 else if (t == typeof(sbyte))
123 ig.Emit (OpCodes.Ldind_I1);
124 else if (t == typeof(ulong))
125 ig.Emit (OpCodes.Ldind_I8);
126 else if (t == typeof(long))
127 ig.Emit (OpCodes.Ldind_I8);
128 else if (t == typeof(float))
129 ig.Emit (OpCodes.Ldind_R4);
130 else if (t == typeof(double))
131 ig.Emit (OpCodes.Ldind_R8);
132 else if (t == typeof(bool))
133 ig.Emit (OpCodes.Ldind_I1);
134 else if (t == typeof(IntPtr))
135 ig.Emit (OpCodes.Ldind_I);
137 if (t == typeof(Enum))
138 ig.Emit (OpCodes.Ldind_Ref);
140 LoadFromPtr (ig, System.Enum.GetUnderlyingType (t));
141 } else if (t.IsValueType)
142 ig.Emit (OpCodes.Ldobj, t);
144 ig.Emit (OpCodes.Ldind_Ref);
147 public static void SaveToPtr (ILGenerator ig, Type t)
149 if (t == typeof(int))
150 ig.Emit (OpCodes.Stind_I4);
151 else if (t == typeof(uint))
152 ig.Emit (OpCodes.Stind_I4);
153 else if (t == typeof(short))
154 ig.Emit (OpCodes.Stind_I2);
155 else if (t == typeof(ushort))
156 ig.Emit (OpCodes.Stind_I2);
157 else if (t == typeof(char))
158 ig.Emit (OpCodes.Stind_I2);
159 else if (t == typeof(byte))
160 ig.Emit (OpCodes.Stind_I1);
161 else if (t == typeof(sbyte))
162 ig.Emit (OpCodes.Stind_I1);
163 else if (t == typeof(ulong))
164 ig.Emit (OpCodes.Stind_I8);
165 else if (t == typeof(long))
166 ig.Emit (OpCodes.Stind_I8);
167 else if (t == typeof(float))
168 ig.Emit (OpCodes.Stind_R4);
169 else if (t == typeof(double))
170 ig.Emit (OpCodes.Stind_R8);
171 else if (t == typeof(bool))
172 ig.Emit (OpCodes.Stind_I1);
173 else if (t == typeof(IntPtr))
174 ig.Emit (OpCodes.Stind_I);
176 if (t == typeof(Enum))
177 ig.Emit (OpCodes.Stind_Ref);
179 SaveToPtr (ig, System.Enum.GetUnderlyingType (t));
180 } else if (t.IsValueType)
181 ig.Emit (OpCodes.Stobj, t);
183 ig.Emit (OpCodes.Stind_Ref);
186 public static bool IsNumber (Type t)
188 switch (Type.GetTypeCode (t))
191 case TypeCode.Double:
196 case TypeCode.Single:
197 case TypeCode.UInt16:
198 case TypeCode.UInt32:
199 case TypeCode.UInt64:
206 public static void GeneratePrimitiveValue ()