2 // codegen.cs: The code generator
5 // Miguel de Icaza (miguel@ximian.com)
7 // (C) 2001 Ximian, Inc.
11 using System.Collections;
12 using System.Reflection;
13 using System.Reflection.Emit;
15 namespace Mono.CSharp {
18 /// Code generator class.
20 public class CodeGen {
21 AppDomain current_domain;
22 AssemblyBuilder assembly_builder;
23 ModuleBuilder module_builder;
25 string Basename (string name)
27 int pos = name.LastIndexOf ("/");
30 return name.Substring (pos + 1);
32 pos = name.LastIndexOf ("\\");
34 return name.Substring (pos + 1);
39 string TrimExt (string name)
41 int pos = name.LastIndexOf (".");
43 return name.Substring (0, pos);
46 public string FileName;
48 public CodeGen (string name, string output)
53 an = new AssemblyName ();
54 an.Name = TrimExt (Basename (name));
55 current_domain = AppDomain.CurrentDomain;
56 assembly_builder = current_domain.DefineDynamicAssembly (
57 an, AssemblyBuilderAccess.RunAndSave);
60 // Pass a path-less name to DefineDynamicModule. Wonder how
61 // this copes with output in different directories then.
62 // FIXME: figure out how this copes with --output /tmp/blah
64 module_builder = assembly_builder.DefineDynamicModule (
65 Basename (name), Basename (output));
69 public AssemblyBuilder AssemblyBuilder {
71 return assembly_builder;
75 public ModuleBuilder ModuleBuilder {
77 return module_builder;
81 public void Save (string name)
84 assembly_builder.Save (Basename (name));
85 } catch (System.IO.IOException io){
86 Report.Error (16, "Coult not write to file `"+name+"', cause: " + io.Message);
92 /// An Emit Context is created for each body of code (from methods,
93 /// properties bodies, indexer bodies or constructor bodies)
95 public class EmitContext {
96 public TypeContainer TypeContainer;
97 public ILGenerator ig;
98 public bool CheckState;
101 /// Whether we are emitting code inside a static or instance method
103 public bool IsStatic;
106 /// The value that is allowed to be returned or NULL if there is no
109 public Type ReturnType;
112 /// Points to the Type (extracted from the TypeContainer) that
113 /// declares this body of code
115 public Type ContainerType;
118 /// Whether this is generating code for a constructor
120 public bool IsConstructor;
123 /// Keeps track of the Type to LocalBuilder temporary storage created
124 /// to store structures (used to compute the address of the structure
125 /// value on structure method invocations)
127 public Hashtable temporary_storage;
129 public Block CurrentBlock;
132 /// The location where we store the return value.
134 LocalBuilder return_value;
137 /// The location where return has to jump to return the
140 public Label ReturnLabel;
143 /// Whether we are in a Finally block
145 public bool InFinally;
148 /// Whether we are in a Try block
153 /// Whether we are in a Catch block
158 /// Location for this EmitContext
162 public EmitContext (TypeContainer parent, Location l, ILGenerator ig,
163 Type return_type, int code_flags, bool is_constructor)
167 TypeContainer = parent;
168 CheckState = RootContext.Checked;
169 IsStatic = (code_flags & Modifiers.STATIC) != 0;
170 ReturnType = return_type;
171 IsConstructor = is_constructor;
173 ContainerType = parent.TypeBuilder;
176 if (ReturnType == TypeManager.void_type)
180 public EmitContext (TypeContainer parent, Location l, ILGenerator ig,
181 Type return_type, int code_flags)
182 : this (parent, l, ig, return_type, code_flags, false)
186 public void EmitTopBlock (Block block, Location loc)
188 bool has_ret = false;
190 // Console.WriteLine ("Emitting: " + loc);
192 int errors = Report.Errors;
194 block.EmitMeta (TypeContainer, ig, block, 0);
196 if (Report.Errors == errors){
197 has_ret = block.Emit (this);
199 if (Report.Errors == errors){
200 if (RootContext.WarningLevel >= 3)
201 block.UsageWarning ();
206 if (ReturnType != null && !has_ret){
208 // FIXME: we need full flow analysis to implement this
211 // Otherwise we report a non-existant error on cs-parser.cs
214 //Report.Error (161, loc, "Not all code paths return a value");
219 if (return_value != null){
220 ig.MarkLabel (ReturnLabel);
221 ig.Emit (OpCodes.Ldloc, return_value);
222 ig.Emit (OpCodes.Ret);
225 ig.Emit (OpCodes.Ret);
230 /// Returns a temporary storage for a variable of type t as
231 /// a local variable in the current body.
233 public LocalBuilder GetTemporaryStorage (Type t)
235 LocalBuilder location;
237 if (temporary_storage == null)
238 temporary_storage = new Hashtable ();
240 location = (LocalBuilder) temporary_storage [t];
241 if (location != null)
244 location = ig.DeclareLocal (t);
245 temporary_storage.Add (t, location);
251 /// Current loop begin and end labels.
253 public Label LoopBegin, LoopEnd;
256 /// Whether we are inside a loop and break/continue are possible.
261 /// Default target in a switch statement. Only valid if
264 public Label DefaultTarget;
267 /// If this is non-null, points to the current switch statement
269 public Switch Switch;
272 /// ReturnValue creates on demand the LocalBuilder for the
273 /// return value from the function. By default this is not
274 /// used. This is only required when returns are found inside
275 /// Try or Catch statements.
277 public LocalBuilder TemporaryReturn ()
279 if (return_value == null){
280 return_value = ig.DeclareLocal (ReturnType);
281 ReturnLabel = ig.DefineLabel ();
288 /// A dynamic This that is shared by all variables in a emitcontext.
289 /// Created on demand.
291 public Expression my_this;
292 public Expression This {
295 my_this = new This (loc).Resolve (this);