2004-10-20 Martin Baulig <martin@ximian.com>
[mono.git] / mcs / class / Mono.CSharp.Debugger / MonoSymbolWriter.cs
index 61f06fafc0b1f2edb2896916d20288015a629b19..10fc8ce88af4dc540bc18f96b2e457de9dbe26b5 100755 (executable)
@@ -1,8 +1,8 @@
 //
-// System.Diagnostics.SymbolStore/MonoSymbolWriter.cs
+// Mono.CSharp.Debugger/MonoSymbolWriter.cs
 //
 // Author:
-//   Martin Baulig (martin@gnome.org)
+//   Martin Baulig (martin@ximian.com)
 //
 // This is the default implementation of the System.Diagnostics.SymbolStore.ISymbolWriter
 // interface.
 // (C) 2002 Ximian, Inc.  http://www.ximian.com
 //
 
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
 using System;
-using System.Reflection;
-using System.Reflection.Emit;
-using System.Diagnostics.SymbolStore;
+using System.Runtime.CompilerServices;
 using System.Collections;
 using System.IO;
        
-namespace Mono.CSharp.Debugger
+namespace Mono.CompilerServices.SymbolWriter
 {
-
-       public class MonoSymbolWriter : IMonoSymbolWriter
+       public interface ISourceFile
        {
-               protected string output_filename = null;
-               protected Hashtable methods = null;
-               protected Hashtable sources = null;
-
-               protected class SourceInfo
-               {
-                       private MethodInfo[] _methods;
-                       public readonly string FileName;
-
-                       public SourceInfo (string filename)
-                       {
-                               this.FileName = filename;
-
-                               this._methods = new MethodInfo [0];
-                       }
+               SourceFileEntry Entry {
+                       get;
+               }
+       }
 
-                       public MethodInfo[] GetMethods ()
-                       {
-                               return _methods;
-                       }
+       public interface ISourceMethod
+       {
+               string Name {
+                       get;
+               }
 
-                       public void AddMethod (MethodInfo method)
-                       {
-                               int i = _methods.Length;
-                               MethodInfo[] new_m = new MethodInfo [i + 1];
-                               Array.Copy (_methods, new_m, i);
-                               new_m [i] = method;
-                               _methods = new_m;
-                       }
+               int NamespaceID {
+                       get;
                }
 
-               protected struct MethodInfo
-               {
-                       public MethodInfo (string name, SourceInfo source_file) {
-                               this.Name = name;
-                               this.SourceFile = source_file;
-                       }
+               int Token {
+                       get;
+               }
+       }
 
-                       public void SetSourceRange (int startLine, int startColumn,
-                                                   int endLine, int endColumn)
-                       {
+       public class MonoSymbolWriter
+       {
+               protected ArrayList locals = null;
+               protected ArrayList methods = null;
+               protected ArrayList sources = null;
+               protected readonly MonoSymbolFile file;
+               private string filename = null;
+               
+               LineNumberEntry [] current_method_lines;
+               int current_method_lines_pos = 0;
+
+               internal ISourceFile[] Sources {
+                       get {
+                               ISourceFile[] retval = new ISourceFile [sources.Count];
+                               sources.CopyTo (retval, 0);
+                               return retval;
                        }
-
-                       public readonly string Name;
-                       public readonly SourceInfo SourceFile;
                }
 
-               protected Object current_method = null;
+               private SourceMethod current_method = null;
 
                //
                // Interface IMonoSymbolWriter
                //
 
-               public MonoSymbolWriter ()
+               public MonoSymbolWriter (string filename)
                {
-                       methods = new Hashtable ();
-                       sources = new Hashtable ();
-               }
-
-               public void Close () {
-                       CreateDwarfFile (output_filename);
-               }
-
-               public void CloseNamespace () {
+                       this.methods = new ArrayList ();
+                       this.sources = new ArrayList ();
+                       this.locals = new ArrayList ();
+                       this.file = new MonoSymbolFile ();
+
+                       this.filename = filename + ".mdb";
+                       
+                       this.current_method_lines = new LineNumberEntry [50];
                }
 
-               public void CloseScope (int endOffset) {
-               }
+               public void CloseNamespace ()
+               }
 
-               // Create and return a new IMonoSymbolDocumentWriter.
-               public ISymbolDocumentWriter DefineDocument (string url,
-                                                            Guid language,
-                                                            Guid languageVendor,
-                                                            Guid documentType)
+               public void DefineLocalVariable (string name, byte[] signature)
                {
-                       return new MonoSymbolDocumentWriter (url);
-               }
+                       if (current_method == null)
+                               return;
 
-               public void DefineField (
-                       SymbolToken parent,
-                       string name,
-                       FieldAttributes attributes,
-                       byte[] signature,
-                       SymAddressKind addrKind,
-                       int addr1,
-                       int addr2,
-                       int addr3)
-               {
+                       current_method.AddLocal (name, signature);
                }
 
-               public void DefineGlobalVariable (
-                       string name,
-                       FieldAttributes attributes,
-                       byte[] signature,
-                       SymAddressKind addrKind,
-                       int addr1,
-                       int addr2,
-                       int addr3)
+               public void MarkSequencePoint (int offset, int line, int column)
                {
-               }
+                       if (current_method == null)
+                               return;
 
-               public void DefineLocalVariable (string name,
-                                                FieldAttributes attributes,
-                                                byte[] signature,
-                                                SymAddressKind addrKind,
-                                                int addr1,
-                                                int addr2,
-                                                int addr3,
-                                                int startOffset,
-                                                int endOffset)
-               {
-                       Console.WriteLine ("WRITE LOCAL: " + name + " " + addr1);
-               }
-
-               public void DefineParameter (
-                       string name,
-                       ParameterAttributes attributes,
-                       int sequence,
-                       SymAddressKind addrKind,
-                       int addr1,
-                       int addr2,
-                       int addr3)
-               {
+                       if (current_method_lines_pos == current_method_lines.Length) {
+                               LineNumberEntry [] tmp = current_method_lines;
+                               current_method_lines = new LineNumberEntry [current_method_lines.Length * 2];
+                               Array.Copy (tmp, current_method_lines, current_method_lines_pos);
+                       }
+                       
+                       current_method_lines [current_method_lines_pos++] = new LineNumberEntry (line, offset);
                }
 
-               public void DefineSequencePoints (
-                       ISymbolDocumentWriter document,
-                       int[] offsets,
-                       int[] lines,
-                       int[] columns,
-                       int[] endLines,
-                       int[] endColumns)
+               public void OpenMethod (ISourceFile file, ISourceMethod method,
+                                       int startRow, int startColumn,
+                                       int endRow, int endColumn)
                {
-               }
+                       SourceMethod source = new SourceMethod (
+                               file, method, startRow, startColumn, endRow, endColumn);
 
-               public void Initialize (IntPtr emitter, string filename, bool fFullBuild)
-               {
-                       throw new NotSupportedException ("Please use the 'Initialize (string filename)' "
-                                                        + "constructor and read the documentation in "
-                                                        + "Mono.CSharp.Debugger/IMonoSymbolWriter.cs");
+                       current_method = source;
+                       methods.Add (current_method);
                }
 
-               // This is documented in IMonoSymbolWriter.cs
-               public void Initialize (string filename)
+               public void CloseMethod ()
                {
-                       this.output_filename = filename;
+                       current_method.SetLineNumbers (
+                               current_method_lines, current_method_lines_pos);
+                       current_method_lines_pos = 0;
+                       
+                       current_method = null;
                }
 
-               public void OpenMethod (SymbolToken method)
+               public SourceFileEntry DefineDocument (string url)
                {
-                       // do nothing
+                       SourceFileEntry entry = new SourceFileEntry (file, url);
+                       sources.Add (entry);
+                       return entry;
                }
 
-               // This is documented in IMonoSymbolWriter.cs
-               public void OpenMethod (SymbolToken symbol_token, string name, string source_file)
+               public int DefineNamespace (string name, SourceFileEntry source,
+                                           string[] using_clauses, int parent)
                {
-                       int token = symbol_token.GetToken ();
-                       SourceInfo source_info;
-
-                       if (methods.ContainsKey (token))
-                               methods.Remove (token);
-
-                       if (sources.ContainsKey (source_file))
-                               source_info = (SourceInfo) sources [source_file];
-                       else {
-                               source_info = new SourceInfo (source_file);
-                               sources.Add (source_file, source_info);
-                       }
-
-                       current_method = new MethodInfo (name, source_info);
-
-                       source_info.AddMethod ((MethodInfo) current_method);
-
-                       methods.Add (token, current_method);
+                       if ((source == null) || (using_clauses == null))
+                               throw new NullReferenceException ();
 
-                       OpenMethod (symbol_token);
+                       return source.DefineNamespace (name, using_clauses, parent);
                }
 
-               public void SetMethodSourceRange (ISymbolDocumentWriter startDoc,
-                                                 int startLine, int startColumn,
-                                                 ISymbolDocumentWriter endDoc,
-                                                 int endLine, int endColumn)
+               public int OpenScope (int startOffset)
                {
-                       if ((startDoc == null) || (endDoc == null))
-                               throw new NullReferenceException ();
-
-                       if (!(startDoc is MonoSymbolDocumentWriter) || !(endDoc is MonoSymbolDocumentWriter))
-                               throw new NotSupportedException ("both startDoc and endDoc must be of type "
-                                                                + "MonoSymbolDocumentWriter");
-
-                       if (!startDoc.Equals (endDoc))
-                               throw new NotSupportedException ("startDoc and endDoc must be the same");
+                       if (current_method == null)
+                               return 0;
 
-                       if (current_method != null)
-                               ((MethodInfo) current_method).SetSourceRange (startLine, startColumn,
-                                                                             endLine, endColumn);
+                       current_method.StartBlock (startOffset);
+                       return 0;
                }
 
-               public void CloseMethod () {
-                       current_method = null;
-               }
-
-               public void OpenNamespace (string name)
+               public void CloseScope (int endOffset)
                {
-               }
+                       if (current_method == null)
+                               return;
 
-               public int OpenScope (int startOffset)
-               {
-                       throw new NotImplementedException ();
+                       current_method.EndBlock (endOffset);
                }
 
-               public void SetScopeRange (int scopeID, int startOffset, int endOffset)
+               protected byte[] CreateOutput (Guid guid)
                {
-               }
+                       foreach (SourceMethod method in methods) {
+                               method.SourceFile.Entry.DefineMethod (
+                                       method.Method.Name, method.Method.Token,
+                                       method.Locals, method.Lines, method.Blocks,
+                                       method.Start.Row, method.End.Row,
+                                       method.Method.NamespaceID);
+                       }
 
-               public void SetSymAttribute (SymbolToken parent, string name, byte[] data)
-               {
+                       return file.CreateSymbolFile (guid);
                }
 
-               public void SetUnderlyingWriter (IntPtr underlyingWriter)
+               public void WriteSymbolFile (Guid guid)
                {
+                       using (FileStream stream = new FileStream (
+                                      filename, FileMode.Create, FileAccess.Write)) {
+                               byte[] data = CreateOutput (guid);
+                               stream.Write (data, 0, data.Length);
+                       }
                }
 
-               public void SetUserEntryPoint (SymbolToken entryMethod)
+               protected class SourceMethod
                {
-               }
+                       LineNumberEntry [] lines;
+                       private ArrayList _locals;
+                       private ArrayList _blocks;
+                       private Stack _block_stack;
+                       private int next_block_id = 0;
+                       private ISourceMethod _method;
+                       private ISourceFile _file;
+                       private LineNumberEntry _start, _end;
+
+                       private LexicalBlockEntry _implicit_block;
+
+                       public SourceMethod (ISourceFile file, ISourceMethod method,
+                                            int startLine, int startColumn,
+                                            int endLine, int endColumn)
+                       {
+                               this._file = file;
+                               this._method = method;
 
-               public void UsingNamespace (string fullName)
-               {
-               }
+                               this._start = new LineNumberEntry (startLine, 0);
+                               this._end = new LineNumberEntry (endLine, 0);
 
-               //
-               // MonoSymbolWriter implementation
-               //
-               protected void WriteMethod (DwarfFileWriter.DieCompileUnit parent_die, MethodInfo method)
-               {
-                       Console.WriteLine ("WRITING METHOD: " + method.Name);
+                               this._implicit_block = new LexicalBlockEntry (0, 0);
+                       }
 
-                       DwarfFileWriter.DieSubProgram die;
+                       public void StartBlock (int startOffset)
+                       {
+                               LexicalBlockEntry block = new LexicalBlockEntry (
+                                       ++next_block_id, startOffset);
+                               if (_block_stack == null)
+                                       _block_stack = new Stack ();
+                               _block_stack.Push (block);
+                               if (_blocks == null)
+                                       _blocks = new ArrayList ();
+                               _blocks.Add (block);
+                       }
 
-                       die = new DwarfFileWriter.DieSubProgram (parent_die, method.Name);
-               }
+                       public void EndBlock (int endOffset)
+                       {
+                               LexicalBlockEntry block =
+                                       (LexicalBlockEntry) _block_stack.Pop ();
 
-               protected void WriteSource (DwarfFileWriter writer, SourceInfo source)
-               {
-                       Console.WriteLine ("WRITING SOURCE: " + source.FileName);
+                               block.Close (endOffset);
+                       }
 
-                       DwarfFileWriter.CompileUnit compile_unit = new DwarfFileWriter.CompileUnit (
-                               writer, source.FileName);
+                       public LexicalBlockEntry[] Blocks {
+                               get {
+                                       if (_blocks == null)
+                                               return new LexicalBlockEntry [0];
+                                       else {
+                                               LexicalBlockEntry[] retval =
+                                                       new LexicalBlockEntry [_blocks.Count];
+                                               _blocks.CopyTo (retval, 0);
+                                               return retval;
+                                       }
+                               }
+                       }
 
-                       DwarfFileWriter.DieCompileUnit die = new DwarfFileWriter.DieCompileUnit (compile_unit);
+                       public LexicalBlockEntry CurrentBlock {
+                               get {
+                                       if ((_block_stack != null) && (_block_stack.Count > 0))
+                                               return (LexicalBlockEntry) _block_stack.Peek ();
+                                       else
+                                               return _implicit_block;
+                               }
+                       }
 
-                       foreach (MethodInfo method in source.GetMethods ())
-                               WriteMethod (die, method);
-               }
+                       public LineNumberEntry[] Lines {
+                               get {
+                                       return lines;
+                               }
+                       }
 
-               protected void CreateDwarfFile (string filename)
-               {
-                       Console.WriteLine ("WRITING DWARF FILE: " + filename);
+                       public LocalVariableEntry[] Locals {
+                               get {
+                                       if (_locals == null)
+                                               return new LocalVariableEntry [0];
+                                       else {
+                                               LocalVariableEntry[] retval =
+                                                       new LocalVariableEntry [_locals.Count];
+                                               _locals.CopyTo (retval, 0);
+                                               return retval;
+                                       }
+                               }
+                       }
 
-                       DwarfFileWriter writer = new DwarfFileWriter (filename);
+                       public void AddLocal (string name, byte[] signature)
+                       {
+                               if (_locals == null)
+                                       _locals = new ArrayList ();
+                               _locals.Add (new LocalVariableEntry (
+                                                    name, signature, CurrentBlock.Index));
+                       }
 
-                       foreach (SourceInfo source in sources.Values)
-                               WriteSource (writer, source);
+                       public ISourceFile SourceFile {
+                               get { return _file; }
+                       }
 
-                       writer.Close ();
+                       public ISourceMethod Method {
+                               get { return _method; }
+                       }
 
-                       Console.WriteLine ("DONE WRITING DWARF FILE");
+                       public LineNumberEntry Start {
+                               get { return _start; }
+                       }
+
+                       public LineNumberEntry End {
+                               get { return _end; }
+                       }
 
+                       //
+                       // Passes on the lines from the MonoSymbolWriter. This method is
+                       // free to mutate the lns array, and it does.
+                       //
+                       internal void SetLineNumbers (LineNumberEntry [] lns, int count)
+                       {
+                               int pos = 0;
+
+                               int last_offset = -1;
+                               int last_row = -1;
+                               for (int i = 0; i < count; i++) {
+                                       LineNumberEntry line = lns [i];
+
+                                       if (line.Offset > last_offset) {
+                                               if (last_row >= 0)
+                                                       lns [pos++] = new LineNumberEntry (
+                                                               last_row, last_offset);
+
+                                               last_row = line.Row;
+                                               last_offset = line.Offset;
+                                       } else if (line.Row > last_row) {
+                                               last_row = line.Row;
+                                       }
+                               }
+                       
+                               lines = new LineNumberEntry [count + ((last_row >= 0) ? 1 : 0)];
+                               Array.Copy (lns, lines, pos);
+                               if (last_row >= 0)
+                                       lines [pos] = new LineNumberEntry (
+                                               last_row, last_offset);
+                       }
                }
        }
 }