2003-04-28 Miguel de Icaza <miguel@ximian.com>
[mono.git] / mcs / mcs / codegen.cs
index bc9ca7b853445a03fc319e2ce350a67a0e8155ce..b10dc6be02c81b9267e52687c8eb5461763bdb49 100755 (executable)
@@ -8,10 +8,10 @@
 //
 
 using System;
+using System.IO;
 using System.Collections;
 using System.Reflection;
 using System.Reflection.Emit;
-using System.Diagnostics.SymbolStore;
 
 namespace Mono.CSharp {
 
@@ -23,7 +23,7 @@ namespace Mono.CSharp {
                public static AssemblyBuilder AssemblyBuilder;
                public static ModuleBuilder   ModuleBuilder;
 
-               static public ISymbolWriter SymbolWriter;
+               static public SymbolWriter SymbolWriter;
 
                public static string Basename (string name)
                {
@@ -62,90 +62,34 @@ namespace Mono.CSharp {
 
                static public string FileName;
 
-               //
-               // This routine initializes the Mono runtime SymbolWriter.
-               //
-               static bool InitMonoSymbolWriter (string basename, string output_file,
-                                                 string[] debug_args)
-               {
-                       string symbol_output = basename + ".dbg";
-
-                       Type itype = SymbolWriter.GetType ();
-                       if (itype == null)
-                               return false;
-
-                       Type[] arg_types = new Type [3];
-                       arg_types [0] = typeof (string);
-                       arg_types [1] = typeof (string);
-                       arg_types [2] = typeof (string[]);
-
-                       MethodInfo initialize = itype.GetMethod ("Initialize", arg_types);
-                       if (initialize == null)
-                               return false;
-
-                       object[] args = new object [3];
-                       args [0] = output_file;
-                       args [1] = symbol_output;
-                       args [2] = debug_args;
-
-                       initialize.Invoke (SymbolWriter, args);
-                       return true;
-               }
-
                //
                // Initializes the symbol writer
                //
-               static void InitializeSymbolWriter (string basename, string output_file,
-                                                   string[] args)
+               static void InitializeSymbolWriter ()
                {
-                       SymbolWriter = ModuleBuilder.GetSymWriter ();
+                       SymbolWriter = SymbolWriter.GetSymbolWriter (ModuleBuilder);
 
                        //
                        // If we got an ISymbolWriter instance, initialize it.
                        //
                        if (SymbolWriter == null) {
-                               Report.Error (
-                                       -18, "Cannot find any symbol writer");
+                               Report.Warning (
+                                       -18, "Could not find the symbol writer assembly (Mono.CSharp.Debugger.dll). This is normally an installation problem. Please make sure to compile and install the mcs/class/Mono.CSharp.Debugger directory.");
                                return;
                        }
-                       
-                       //
-                       // Due to lacking documentation about the first argument of the
-                       // Initialize method, we cannot use Microsoft's default symbol
-                       // writer yet.
-                       //
-                       // If we're using the mono symbol writer, the SymbolWriter object
-                       // is of type MonoSymbolWriter - but that's defined in a dynamically
-                       // loaded DLL - that's why we're doing a comparision based on the type
-                       // name here instead of using `SymbolWriter is MonoSymbolWriter'.
-                       //
-                       Type sym_type = ((object) SymbolWriter).GetType ();
-                       
-                       switch (sym_type.Name){
-                       case "MonoSymbolWriter":
-                               if (!InitMonoSymbolWriter (basename, output_file, args))
-                                       Report.Error (
-                                               -18, "Cannot initialize the symbol writer");
-                               break;
-
-                       default:
-                               Report.Error (
-                                       -18, "Cannot generate debugging information on this platform");
-                               break;
-                       }
                }
 
                //
                // Initializes the code generator variables
                //
-               static public void Init (string name, string output, bool want_debugging_support,
-                                        string[] debug_args)
+               static public void Init (string name, string output, bool want_debugging_support)
                {
                        AssemblyName an;
 
                        FileName = output;
                        an = new AssemblyName ();
-                       an.Name = TrimExt (Basename (name));
+                       an.Name = Path.GetFileNameWithoutExtension (name);
+                       
                        current_domain = AppDomain.CurrentDomain;
                        AssemblyBuilder = current_domain.DefineDynamicAssembly (
                                an, AssemblyBuilderAccess.RunAndSave, Dirname (name));
@@ -161,17 +105,8 @@ namespace Mono.CSharp {
                        ModuleBuilder = AssemblyBuilder.DefineDynamicModule (
                                Basename (name), Basename (output), want_debugging_support);
 
-                       if (want_debugging_support) {
-                               int pos = output.LastIndexOf (".");
-
-                               string basename;
-                               if (pos > 0)
-                                       basename = output.Substring (0, pos);
-                               else
-                                       basename = output;
-
-                               InitializeSymbolWriter (basename, output, debug_args);
-                       }
+                       if (want_debugging_support)
+                               InitializeSymbolWriter ();
                }
 
                static public void Save (string name)
@@ -179,20 +114,7 @@ namespace Mono.CSharp {
                        try {
                                AssemblyBuilder.Save (Basename (name));
                        } catch (System.IO.IOException io){
-                               Report.Error (16, "Coult not write to file `"+name+"', cause: " + io.Message);
-                       }
-               }
-
-               static public void SaveSymbols ()
-               {
-                       if (SymbolWriter != null) {
-                               // If we have a symbol writer, call its Close() method to write
-                               // the symbol file to disk.
-                               //
-                               // When using Mono's default symbol writer, the Close() method must
-                               // be called after the assembly has already been written to disk since
-                               // it opens the assembly and reads its metadata.
-                               SymbolWriter.Close ();
+                               Report.Error (16, "Could not write to file `"+name+"', cause: " + io.Message);
                        }
                }
        }
@@ -203,7 +125,7 @@ namespace Mono.CSharp {
        /// </summary>
        public class EmitContext {
                public DeclSpace DeclSpace;
-               public TypeContainer TypeContainer;
+               public DeclSpace TypeContainer;
                public ILGenerator   ig;
 
                /// <summary>
@@ -267,6 +189,8 @@ namespace Mono.CSharp {
 
                public Block CurrentBlock;
 
+               public int CurrentFile;
+
                /// <summary>
                ///   The location where we store the return value.
                /// </summary>
@@ -293,6 +217,17 @@ namespace Mono.CSharp {
                /// </summary>
                public bool InTry;
 
+               /// <summary>
+               ///   Whether we are inside an iterator block.
+               /// </summary>
+               public bool InIterator;
+               
+               /// <summary>
+               ///   Whether remapping of locals, parameters and fields is turned on.
+               ///   Used by iterators and anonymous methods.
+               /// </summary>
+               public bool RemapToProxy;
+
                /// <summary>
                ///   Whether we are in a Catch block
                /// </summary>
@@ -304,9 +239,9 @@ namespace Mono.CSharp {
                public bool InUnsafe;
 
                /// <summary>
-               ///   Whether we break from a loop or not
+               ///  Whether we are inside an anonymous method.
                /// </summary>
-               public bool Breaks;
+               public bool InAnonymousMethod;
                
                /// <summary>
                ///   Location for this EmitContext
@@ -332,7 +267,7 @@ namespace Mono.CSharp {
 
                protected Stack FlowStack;
                
-               public EmitContext (TypeContainer parent, DeclSpace ds, Location l, ILGenerator ig,
+               public EmitContext (DeclSpace parent, DeclSpace ds, Location l, ILGenerator ig,
                                    Type return_type, int code_flags, bool is_constructor)
                {
                        this.ig = ig;
@@ -343,9 +278,12 @@ namespace Mono.CSharp {
                        ConstantCheckState = true;
                        
                        IsStatic = (code_flags & Modifiers.STATIC) != 0;
+                       InIterator = (code_flags & Modifiers.METHOD_YIELDS) != 0;
+                       RemapToProxy = InIterator;
                        ReturnType = return_type;
                        IsConstructor = is_constructor;
                        CurrentBlock = null;
+                       CurrentFile = 0;
                        
                        if (parent != null){
                                // Can only be null for the ResolveType contexts.
@@ -488,12 +426,11 @@ namespace Mono.CSharp {
                {
                        bool has_ret = false;
 
-//                     Console.WriteLine ("Emitting: " + loc);
-
-                       if (CodeGen.SymbolWriter != null)
-                               Mark (loc);
+                       if (!Location.IsNull (loc))
+                               CurrentFile = loc.File;
 
                        if (block != null){
+                           try {
                                int errors = Report.Errors;
 
                                block.EmitMeta (this, block);
@@ -512,17 +449,32 @@ namespace Mono.CSharp {
                                        }
 
                                        cfb = (FlowBranching) FlowStack.Pop ();
-                                       cfb.MergeTopBlock ();
+                                       FlowReturns returns = cfb.MergeTopBlock ();
 
                                        DoFlowAnalysis = old_do_flow_analysis;
 
                                        has_ret = block.Emit (this);
 
+                                       if ((returns == FlowReturns.ALWAYS) ||
+                                           (returns == FlowReturns.EXCEPTION) ||
+                                           (returns == FlowReturns.UNREACHABLE))
+                                               has_ret = true;
+
                                        if (Report.Errors == errors){
                                                if (RootContext.WarningLevel >= 3)
                                                        block.UsageWarning ();
                                        }
                                }
+                           } catch {
+                                       Console.WriteLine ("Exception caught by the compiler while compiling:");
+                                       Console.WriteLine ("   Block that caused the problem begin at: " + loc);
+                                       
+                                       if (CurrentBlock != null){
+                                               Console.WriteLine ("                     Block being compiled: [{0},{1}]",
+                                                                  CurrentBlock.StartLocation, CurrentBlock.EndLocation);
+                                       }
+                                       throw;
+                           }
                        }
 
                        if (ReturnType != null && !has_ret){
@@ -531,8 +483,10 @@ namespace Mono.CSharp {
                                // correctly and emit an error instead of a warning.
                                //
                                //
-                               Report.Error (161, loc, "Not all code paths return a value");
-                               return;
+                               if (!InIterator){
+                                       Report.Error (161, loc, "Not all code paths return a value");
+                                       return;
+                               }
                        }
 
                        if (HasReturnLabel)
@@ -542,6 +496,9 @@ namespace Mono.CSharp {
                                ig.Emit (OpCodes.Ret);
                        } else {
                                if (!InTry){
+                                       if (InIterator)
+                                               has_ret = true;
+                                       
                                        if (!has_ret || HasReturnLabel)
                                                ig.Emit (OpCodes.Ret);
                                }
@@ -552,15 +509,16 @@ namespace Mono.CSharp {
                ///   This is called immediately before emitting an IL opcode to tell the symbol
                ///   writer to which source line this opcode belongs.
                /// </summary>
-               public void Mark (Location loc)
+               public void Mark (Location loc, bool check_file)
                {
-                       if (!Location.IsNull (loc)) {
-                               ISymbolDocumentWriter doc = loc.SymbolDocument;
+                       if ((CodeGen.SymbolWriter == null) || Location.IsNull (loc))
+                               return;
 
-                               if (doc != null)
-                                       ig.MarkSequencePoint (doc, loc.Row, 0,  loc.Row, 0);
-                       }               }
+                       if (check_file && (CurrentFile != loc.File))
+                               return;
 
+                       ig.MarkSequencePoint (null, loc.Row, 0, 0, 0);
+               }
 
                /// <summary>
                ///   Returns a temporary storage for a variable of type t as 
@@ -635,6 +593,34 @@ namespace Mono.CSharp {
                        return return_value;
                }
 
+               //
+               // Creates a field `name' with the type `t' on the proxy class
+               //
+               public FieldBuilder MapVariable (string name, Type t)
+               {
+                       if (InIterator){
+                               return IteratorHandler.Current.MapVariable (name, t);
+                       }
+
+                       throw new Exception ("MapVariable for an unknown state");
+               }
+
+               //
+               // Emits the proper object to address fields on a remapped
+               // variable/parameter to field in anonymous-method/iterator proxy classes.
+               //
+               public void EmitThis ()
+               {
+                       ig.Emit (OpCodes.Ldarg_0);
+
+                       if (!IsStatic){
+                               if (InIterator)
+                                       ig.Emit (OpCodes.Ldfld, IteratorHandler.Current.this_field);
+                               else
+                                       throw new Exception ("EmitThis for an unknown state");
+                       }
+               }
+
                /// <summary>
                ///   A dynamic This that is shared by all variables in a emitcontext.
                ///   Created on demand.