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 public static 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 DeclSpace DeclSpace;
97 public TypeContainer TypeContainer;
98 public ILGenerator ig;
101 /// This variable tracks the `checked' state of the compilation,
102 /// it controls whether we should generate code that does overflow
103 /// checking, or if we generate code that ignores overflows.
105 /// The default setting comes from the command line option to generate
106 /// checked or unchecked code plus any source code changes using the
107 /// checked/unchecked statements or expressions. Contrast this with
108 /// the ConstantCheckState flag.
111 public bool CheckState;
114 /// The constant check state is always set to `true' and cant be changed
115 /// from the command line. The source code can change this setting with
116 /// the `checked' and `unchecked' statements and expressions.
118 public bool ConstantCheckState;
121 /// Whether we are emitting code inside a static or instance method
123 public bool IsStatic;
126 /// The value that is allowed to be returned or NULL if there is no
129 public Type ReturnType;
132 /// Points to the Type (extracted from the TypeContainer) that
133 /// declares this body of code
135 public Type ContainerType;
138 /// Whether this is generating code for a constructor
140 public bool IsConstructor;
143 /// Keeps track of the Type to LocalBuilder temporary storage created
144 /// to store structures (used to compute the address of the structure
145 /// value on structure method invocations)
147 public Hashtable temporary_storage;
149 public Block CurrentBlock;
152 /// The location where we store the return value.
154 LocalBuilder return_value;
157 /// The location where return has to jump to return the
160 public Label ReturnLabel;
163 /// Whether we are in a Finally block
165 public bool InFinally;
168 /// Whether we are in a Try block
173 /// Whether we are in a Catch block
178 /// Whether we are inside an unsafe block
180 public bool InUnsafe;
183 /// Location for this EmitContext
187 public EmitContext (TypeContainer parent, DeclSpace ds, Location l, ILGenerator ig,
188 Type return_type, int code_flags, bool is_constructor)
192 TypeContainer = parent;
194 CheckState = RootContext.Checked;
195 ConstantCheckState = true;
197 IsStatic = (code_flags & Modifiers.STATIC) != 0;
198 ReturnType = return_type;
199 IsConstructor = is_constructor;
201 ContainerType = parent.TypeBuilder;
202 InUnsafe = ((parent.ModFlags | code_flags) & Modifiers.UNSAFE) != 0;
205 if (ReturnType == TypeManager.void_type)
209 public EmitContext (TypeContainer tc, Location l, ILGenerator ig,
210 Type return_type, int code_flags, bool is_constructor)
211 : this (tc, tc, l, ig, return_type, code_flags, is_constructor)
215 public EmitContext (TypeContainer tc, Location l, ILGenerator ig,
216 Type return_type, int code_flags)
217 : this (tc, tc, l, ig, return_type, code_flags, false)
221 public void EmitTopBlock (Block block, Location loc)
223 bool has_ret = false;
225 // Console.WriteLine ("Emitting: " + loc);
227 int errors = Report.Errors;
229 block.EmitMeta (this, block, 0);
231 if (Report.Errors == errors){
232 has_ret = block.Emit (this);
234 if (Report.Errors == errors){
235 if (RootContext.WarningLevel >= 3)
236 block.UsageWarning ();
241 if (ReturnType != null && !has_ret){
243 // FIXME: we need full flow analysis to implement this
244 // correctly and emit an error instead of a warning.
247 Report.Error (161, loc, "Not all code paths return a value");
251 if (return_value != null){
252 ig.MarkLabel (ReturnLabel);
253 ig.Emit (OpCodes.Ldloc, return_value);
254 ig.Emit (OpCodes.Ret);
258 ig.Emit (OpCodes.Ret);
264 /// Returns a temporary storage for a variable of type t as
265 /// a local variable in the current body.
267 public LocalBuilder GetTemporaryStorage (Type t)
269 LocalBuilder location;
271 if (temporary_storage != null){
272 location = (LocalBuilder) temporary_storage [t];
273 if (location != null)
277 location = ig.DeclareLocal (t);
282 public void FreeTemporaryStorage (LocalBuilder b)
288 /// Current loop begin and end labels.
290 public Label LoopBegin, LoopEnd;
293 /// Whether we are inside a loop and break/continue are possible.
298 /// Default target in a switch statement. Only valid if
301 public Label DefaultTarget;
304 /// If this is non-null, points to the current switch statement
306 public Switch Switch;
309 /// ReturnValue creates on demand the LocalBuilder for the
310 /// return value from the function. By default this is not
311 /// used. This is only required when returns are found inside
312 /// Try or Catch statements.
314 public LocalBuilder TemporaryReturn ()
316 if (return_value == null){
317 return_value = ig.DeclareLocal (ReturnType);
318 ReturnLabel = ig.DefineLabel ();
325 /// A dynamic This that is shared by all variables in a emitcontext.
326 /// Created on demand.
328 public Expression my_this;
329 public Expression This {
332 my_this = new This (loc).Resolve (this);