1 //
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:
9 //
10 // The above copyright notice and this permission notice shall be
11 // included in all copies or substantial portions of the Software.
12 //
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.
20 //
21 // Copyright (C) Lluis Sanchez Gual, 2004
22 //
23 
24 #if !FULL_AOT_RUNTIME
25 using System;
26 using System.Collections;
27 using System.IO;
28 using System.Reflection;
29 using System.Reflection.Emit;
30 
31 namespace Mono.CodeGeneration
32 {
33 	public class CodeMethod
34 	{
35 		MethodBase methodBase;
36 		CodeBuilder builder;
37 		string name;
38 		MethodAttributes attributes;
39 		Type returnType;
40 		TypeBuilder typeBuilder;
41 		Type[] parameterTypes;
42 		ArrayList customAttributes = new ArrayList ();
43 		CodeClass cls;
44 
DefineMethod(CodeClass cls, string name, MethodAttributes attributes, Type returnType, Type[] parameterTypes)45 		internal static CodeMethod DefineMethod (CodeClass cls, string name, MethodAttributes attributes, Type returnType, Type[] parameterTypes)
46 		{
47 			return new CodeMethod (cls, name, attributes, returnType, parameterTypes);
48 		}
49 
DefineConstructor(CodeClass cls, MethodAttributes attributes, Type[] parameterTypes)50 		public static CodeMethod DefineConstructor (CodeClass cls, MethodAttributes attributes, Type[] parameterTypes)
51 		{
52 			return new CodeMethod (cls, attributes, parameterTypes);
53 		}
54 
CodeMethod(CodeClass cls, string name, MethodAttributes attributes, Type returnType, Type[] parameterTypes)55 		internal CodeMethod (CodeClass cls, string name, MethodAttributes attributes, Type returnType, Type[] parameterTypes)
56 		{
57 			this.cls = cls;
58 			this.typeBuilder = cls.TypeBuilder;
59 			this.name = name;
60 			this.attributes = attributes;
61 			this.returnType = returnType;
62 			this.parameterTypes = parameterTypes;
63 
64 			methodBase = typeBuilder.DefineMethod (name, attributes, returnType, parameterTypes);
65 			builder = new CodeBuilder (cls);
66 		}
67 
CodeMethod(CodeClass cls, MethodAttributes attributes, Type[] parameterTypes)68 		CodeMethod (CodeClass cls, MethodAttributes attributes, Type[] parameterTypes)
69 		{
70 			this.cls = cls;
71 			this.typeBuilder = cls.TypeBuilder;
72 			this.attributes = attributes;
73 			this.parameterTypes = parameterTypes;
74 			this.name = typeBuilder.Name;
75 
76 			methodBase = typeBuilder.DefineConstructor (attributes, CallingConventions.Standard, parameterTypes);
77 			builder = new CodeBuilder (cls);
78 		}
79 
80 		public TypeBuilder DeclaringType
81 		{
82 			get { return typeBuilder; }
83 		}
84 
85 		public MethodInfo MethodInfo
86 		{
87 			get { return methodBase as MethodInfo; }
88 		}
89 
90 		public MethodBase MethodBase
91 		{
92 			get { return methodBase; }
93 		}
94 
95 		public string Name
96 		{
97 			get { return name; }
98 		}
99 
100 		public MethodAttributes Attributes
101 		{
102 			get { return attributes; }
103 		}
104 
105 		public Type ReturnType
106 		{
107 			get { return returnType; }
108 		}
109 
110 		public Type[] ParameterTypes
111 		{
112 			get { return parameterTypes; }
113 		}
114 
115 		public CodeBuilder CodeBuilder
116 		{
117 			get { return builder; }
118 		}
119 
120 		public bool IsStatic
121 		{
122 			get { return (attributes & MethodAttributes.Static) != 0; }
123 		}
124 
CreateCustomAttribute(Type attributeType)125 		public CodeCustomAttribute CreateCustomAttribute (Type attributeType)
126 		{
127 			return CreateCustomAttribute (attributeType,
128 				Type.EmptyTypes, new object [0]);
129 		}
130 
CreateCustomAttribute(Type attributeType, Type [] ctorArgTypes, object [] ctorArgs)131 		public CodeCustomAttribute CreateCustomAttribute (Type attributeType, Type [] ctorArgTypes, object [] ctorArgs)
132 		{
133 			return CreateCustomAttribute (attributeType,
134 				ctorArgTypes, ctorArgs, new string [0], new object [0]);
135 		}
136 
CreateCustomAttribute(Type attributeType, Type [] ctorArgTypes, object [] ctorArgs, string [] namedArgFieldNames, object [] namedArgValues)137 		public CodeCustomAttribute CreateCustomAttribute (Type attributeType, Type [] ctorArgTypes, object [] ctorArgs, string [] namedArgFieldNames, object [] namedArgValues)
138 		{
139 			CodeCustomAttribute cca = CodeCustomAttribute.Create (
140 				attributeType, ctorArgTypes, ctorArgs, namedArgFieldNames, namedArgValues);
141 			SetCustomAttribute (cca);
142 			return cca;
143 		}
144 
CreateCustomAttribute(Type attributeType, Type [] ctorArgTypes, CodeLiteral [] ctorArgs, FieldInfo [] fields, CodeLiteral [] fieldValues)145 		public CodeCustomAttribute CreateCustomAttribute (Type attributeType, Type [] ctorArgTypes, CodeLiteral [] ctorArgs, FieldInfo [] fields, CodeLiteral [] fieldValues)
146 		{
147 			CodeCustomAttribute cca = CodeCustomAttribute.Create (
148 				attributeType, ctorArgTypes, ctorArgs, fields, fieldValues);
149 			SetCustomAttribute (cca);
150 			return cca;
151 		}
152 
SetCustomAttribute(CodeCustomAttribute cca)153 		void SetCustomAttribute (CodeCustomAttribute cca)
154 		{
155 			if (methodBase is MethodBuilder)
156 				((MethodBuilder) methodBase).SetCustomAttribute (cca.Builder);
157 			else if (methodBase is ConstructorBuilder)
158 				((ConstructorBuilder) methodBase).SetCustomAttribute (cca.Builder);
159 			customAttributes.Add (cca);
160 		}
161 
PrintCode()162 		public string PrintCode ()
163 		{
164 			StringWriter sw = new StringWriter ();
165 			CodeWriter cw = new CodeWriter (sw);
166 			PrintCode (cw);
167 			return sw.ToString ();
168 		}
169 
PrintCode(CodeWriter cp)170 		public virtual void PrintCode (CodeWriter cp)
171 		{
172 			cp.BeginLine ();
173 			foreach (CodeCustomAttribute a in customAttributes)
174 				a.PrintCode (cp);
175 			if ((methodBase.Attributes & MethodAttributes.Static) != 0)
176 				cp.Write ("static ");
177 			if ((methodBase.Attributes & MethodAttributes.Public) != 0)
178 				cp.Write ("public ");
179 			if (returnType != null) cp.Write (returnType + " ");
180 			cp.Write (name + " (");
181 			for (int n=0; n<parameterTypes.Length; n++) {
182 				if (n > 0) cp.Write (", ");
183 				cp.Write (parameterTypes[n] + " arg" + n);
184 			}
185 			cp.Write (")");
186 			cp.EndLine ();
187 			cp.WriteLineInd ("{");
188 
189 			builder.PrintCode (cp);
190 
191 			cp.WriteLineUnind ("}");
192 		}
193 
GetArg(int n)194 		public CodeArgumentReference GetArg (int n)
195 		{
196 			if (n < 0 || n >= parameterTypes.Length)
197 				throw new InvalidOperationException ("Invalid argument number");
198 
199 			int narg = IsStatic ? n : n + 1;
200 			return new CodeArgumentReference (parameterTypes[n], narg, "arg" + n);
201 		}
202 
GetThis()203 		public CodeArgumentReference GetThis ()
204 		{
205 			if (IsStatic)
206 				throw new InvalidOperationException ("'this' not available in static methods");
207 
208 			return new CodeArgumentReference (DeclaringType, 0, "this");
209 		}
210 
Generate()211 		public void Generate ()
212 		{
213 			ILGenerator gen = methodBase is MethodInfo ? ((MethodBuilder)methodBase).GetILGenerator() : ((ConstructorBuilder)methodBase).GetILGenerator();
214 			Label returnLabel = gen.DefineLabel ();
215 			builder.ReturnLabel = returnLabel;
216 			builder.Generate (gen);
217 			gen.MarkLabel(returnLabel);
218 			gen.Emit(OpCodes.Ret);
219 		}
220 
UpdateMethodBase(Type type)221 		public void UpdateMethodBase (Type type)
222 		{
223 			if (methodBase is MethodInfo)
224 				methodBase = type.GetMethod (methodBase.Name, parameterTypes);
225 			else
226 				methodBase = type.GetConstructor (parameterTypes);
227 		}
228 	}
229 }
230 #endif
231