2001-10-30 Ravi Pratap <ravi@ximian.com>
[mono.git] / mcs / mcs / codegen.cs
1 //
2 // codegen.cs: The code generator
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //
7 // (C) 2001 Ximian, Inc.
8 //
9
10 using System;
11 using System.Collections;
12 using System.Reflection;
13 using System.Reflection.Emit;
14
15 namespace CIR {
16         
17         public class CodeGen {
18                 AppDomain current_domain;
19                 AssemblyBuilder assembly_builder;
20                 ModuleBuilder   module_builder;
21
22                 string Basename (string name)
23                 {
24                         int pos = name.LastIndexOf ("/");
25
26                         if (pos != -1)
27                                 return name.Substring (pos + 1);
28
29                         pos = name.LastIndexOf ("\\");
30                         if (pos != -1)
31                                 return name.Substring (pos + 1);
32
33                         return name;
34                 }
35
36                 string TrimExt (string name)
37                 {
38                         int pos = name.LastIndexOf (".");
39
40                         return name.Substring (0, pos);
41                 }
42                 
43                 public CodeGen (string name, string output)
44                 {
45                         AssemblyName an;
46                         
47                         an = new AssemblyName ();
48                         an.Name = TrimExt (name);
49                         current_domain = AppDomain.CurrentDomain;
50                         assembly_builder = current_domain.DefineDynamicAssembly (
51                                 an, AssemblyBuilderAccess.RunAndSave);
52
53                         //
54                         // Pass a path-less name to DefineDynamicModule.  Wonder how
55                         // this copes with output in different directories then.
56                         // FIXME: figure out how this copes with --output /tmp/blah
57                         //
58                         module_builder = assembly_builder.DefineDynamicModule (
59                                 Basename (name), Basename (output));
60
61                 }
62                 
63                 public AssemblyBuilder AssemblyBuilder {
64                         get {
65                                 return assembly_builder;
66                         }
67                 }
68                 
69                 public ModuleBuilder ModuleBuilder {
70                         get {
71                                 return module_builder;
72                         }
73                 }
74                 
75                 public void Save (string name)
76                 {
77                         try {
78                                 assembly_builder.Save (Basename (name));
79                         } catch (System.IO.IOException io){
80                                 Report.Error (16, "Coult not write to file `"+name+"', cause: " + io.Message);
81                         }
82                 }
83         }
84
85         public class EmitContext {
86                 public TypeContainer TypeContainer;
87                 public ILGenerator   ig;
88                 public bool CheckState;
89
90                 // <summary>
91                 //   Whether we are emitting code inside a static or instance method
92                 // </summary>
93                 public bool IsStatic;
94
95                 // <summary>
96                 //   The value that is allowed to be returned or NULL if there is no
97                 //   return type.
98                 // </summary>
99                 public Type ReturnType;
100
101                 // <summary>
102                 //   Whether this is generating code for a constructor
103                 // </summary>
104                 public bool IsConstructor;
105                 
106                 // <summary>
107                 //   Keeps track of the Type to LocalBuilder temporary storage created
108                 //   to store structures (used to compute the address of the structure
109                 //   value on structure method invocations)
110                 // </summary>
111                 public Hashtable temporary_storage;
112
113                 public Block CurrentBlock;
114                 
115                 public EmitContext (TypeContainer parent, ILGenerator ig, Type return_type,
116                                     int code_flags, bool is_constructor)
117                 {
118                         this.ig = ig;
119
120                         TypeContainer = parent;
121                         CheckState = parent.RootContext.Checked;
122                         IsStatic = (code_flags & Modifiers.STATIC) != 0;
123                         ReturnType = return_type;
124                         IsConstructor = is_constructor;
125                         CurrentBlock = null;
126                         
127                         if (ReturnType == TypeManager.void_type)
128                                 ReturnType = null;
129                 }
130
131                 public EmitContext (TypeContainer parent, ILGenerator ig, Type return_type, int code_flags)
132                         : this (parent, ig, return_type, code_flags, false)
133                 {
134                 }
135
136                 public void EmitTopBlock (Block block)
137                 {
138                         bool has_ret = false;
139                         
140                         if (block != null){
141                                 int errors = Report.Errors;
142                                 
143                                 block.EmitMeta (TypeContainer, ig, block, 0);
144                                 
145                                 if (Report.Errors == errors){
146                                         has_ret = block.Emit (this);
147                                         
148                                         if (Report.Errors == errors)
149                                                 block.UsageWarning ();
150                                 }
151                         }
152
153                         if (!has_ret)
154                                 ig.Emit (OpCodes.Ret);
155                 }
156
157                 // <summary>
158                 //   Returns a temporary storage for a variable of type t as 
159                 //   a local variable in the current body.
160                 // </summary>
161                 public LocalBuilder GetTemporaryStorage (Type t)
162                 {
163                         LocalBuilder location;
164                         
165                         if (temporary_storage == null)
166                                 temporary_storage = new Hashtable ();
167
168                         location = (LocalBuilder) temporary_storage [t];
169                         if (location != null)
170                                 return location;
171
172                         location = ig.DeclareLocal (t);
173                         temporary_storage.Add (t, location);
174
175                         return location;
176                 }
177
178                 //
179                 // Current loop begin and end labels.
180                 //
181                 public Label LoopBegin, LoopEnd;
182
183                 //
184                 // Whether we are inside a loop and break/continue are possible.
185                 // 
186                 public bool  InLoop;
187
188                 //
189                 // Whether we are currently emitting code for a ref/out parameter
190                 //
191                 public bool  RefOrOutParameter;
192                 
193         }
194 }