2004-10-20 Martin Baulig <martin@ximian.com>
[mono.git] / mcs / class / Mono.CSharp.Debugger / MonoSymbolWriter.cs
index f055acd2a618654b91f7601f802dd9a1d10f8ca2..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.Runtime.CompilerServices;
-using System.Diagnostics.SymbolStore;
 using System.Collections;
 using System.IO;
        
-namespace Mono.CSharp.Debugger
+namespace Mono.CompilerServices.SymbolWriter
 {
-       internal class SourceFile : SourceFileEntry, ISymbolDocumentWriter
+       public interface ISourceFile
        {
-               private ArrayList _methods = new ArrayList ();
-
-               public SourceFile (MonoSymbolFile file, string filename)
-                       : base (file, filename)
-               { }
-
-               public new SourceMethod[] Methods {
-                       get {
-                               SourceMethod[] retval = new SourceMethod [_methods.Count];
-                               _methods.CopyTo (retval);
-                               return retval;
-                       }
-               }
-
-               public void AddMethod (SourceMethod method)
-               {
-                       _methods.Add (method);
-               }
-
-               void ISymbolDocumentWriter.SetCheckSum (Guid algorithmId, byte[] checkSum)
-               {
-                       throw new NotSupportedException ();
-               }
-
-               void ISymbolDocumentWriter.SetSource (byte[] source)
-               {
-                       throw new NotSupportedException ();
+               SourceFileEntry Entry {
+                       get;
                }
        }
 
-       internal class SourceMethod
+       public interface ISourceMethod
        {
-               private ArrayList _lines = new ArrayList ();
-               private ArrayList _locals = new ArrayList ();
-               private ArrayList _blocks = new ArrayList ();
-               private Stack _block_stack = new Stack ();
-               private int next_block_id = 0;
-
-               internal readonly MethodBase _method_base;
-               internal SourceFile _source_file;
-               internal int _token;
-               private int _namespace_id;
-               private LineNumberEntry _start, _end;
-               private MonoSymbolFile _file;
-
-               private LexicalBlockEntry _implicit_block;
-
-               internal SourceMethod (MonoSymbolFile file, SourceFile source_file,
-                                      int startLine, int startColumn, int endLine, int endColumn,
-                                      MethodBase method_base, int namespace_id)
-               {
-                       this._file = file;
-                       this._method_base = method_base;
-                       this._source_file = source_file;
-                       this._namespace_id = namespace_id;
-
-                       this._start = new LineNumberEntry (startLine, 0);
-                       this._end = new LineNumberEntry (endLine, 0);
-
-                       this._implicit_block = new LexicalBlockEntry (0, 0);
-               }
-
-               public void StartBlock (int startOffset)
-               {
-                       LexicalBlockEntry block = new LexicalBlockEntry (++next_block_id, startOffset);
-                       _block_stack.Push (block);
-                       _blocks.Add (block);
-               }
-
-               public void EndBlock (int endOffset)
-               {
-                       LexicalBlockEntry block = (LexicalBlockEntry) _block_stack.Pop ();
-
-                       block.Close (endOffset);
-               }
-
-               public LexicalBlockEntry[] Blocks {
-                       get {
-                               LexicalBlockEntry[] retval = new LexicalBlockEntry [_blocks.Count];
-                               _blocks.CopyTo (retval, 0);
-                               return retval;
-                       }
-               }
-
-               public LexicalBlockEntry CurrentBlock {
-                       get {
-                               if (_block_stack.Count > 0)
-                                       return (LexicalBlockEntry) _block_stack.Peek ();
-                               else
-                                       return _implicit_block;
-                       }
-               }
-
-               public LineNumberEntry[] Lines {
-                       get {
-                               LineNumberEntry[] retval = new LineNumberEntry [_lines.Count];
-                               _lines.CopyTo (retval);
-                               return retval;
-                       }
-               }
-
-               public void AddLine (LineNumberEntry line)
-               {
-                       _lines.Add (line);
+               string Name {
+                       get;
                }
 
-               public LocalVariableEntry[] Locals {
-                       get {
-                               LocalVariableEntry[] retval = new LocalVariableEntry [_locals.Count];
-                               _locals.CopyTo (retval, 0);
-                               return retval;
-                       }
-               }
-
-               public void AddLocal (string name, FieldAttributes attributes, byte[] signature)
-               {
-                       _locals.Add (new LocalVariableEntry (name, attributes, signature, CurrentBlock.Index));
+               int NamespaceID {
+                       get;
                }
 
-               public MethodBase MethodBase {
-                       get {
-                               return _method_base;
-                       }
-               }
-
-               public string FullName {
-                       get {
-                               return _method_base.DeclaringType.FullName + "." + _method_base.Name;
-                       }
-               }
-
-               public Type ReturnType {
-                       get {
-                               if (_method_base is MethodInfo)
-                                       return ((MethodInfo)_method_base).ReturnType;
-                               else if (_method_base is ConstructorInfo)
-                                       return _method_base.DeclaringType;
-                               else
-                                       throw new NotSupportedException ();
-                       }
-               }
-
-               public ParameterInfo[] Parameters {
-                       get {
-                               if (_method_base == null)
-                                       return new ParameterInfo [0];
-
-                               ParameterInfo [] retval = _method_base.GetParameters ();
-                               if (retval == null)
-                                       return new ParameterInfo [0];
-                               else
-                                       return retval;
-                       }
-               }
-
-               public SourceFile SourceFile {
-                       get {
-                               return _source_file;
-                       }
-               }
-
-               public int Token {
-                       get {
-                               if (_token != 0)
-                                       return _token;
-                               else
-                                       throw new NotSupportedException ();
-                       }
-               }
-
-               public bool HasSource {
-                       get {
-                               return _source_file != null;
-                       }
-               }
-
-               public LineNumberEntry Start {
-                       get {
-                               return _start;
-                       }
-               }
-
-               public LineNumberEntry End {
-                       get {
-                               return _end;
-                       }
-               }
-
-               public int NamespaceID {
-                       get {
-                               return _namespace_id;
-                       }
+               int Token {
+                       get;
                }
        }
 
-       public class MonoSymbolWriter : IMonoSymbolWriter
+       public class MonoSymbolWriter
        {
-               protected ModuleBuilder module_builder;
                protected ArrayList locals = null;
-               protected ArrayList orphant_methods = null;
                protected ArrayList methods = null;
-               protected Hashtable sources = null;
-               private MonoSymbolFile file = null;
-
-               internal SourceMethod[] Methods {
+               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 {
-                               SourceMethod[] retval = new SourceMethod [methods.Count];
-                               methods.CopyTo (retval);
-                               return retval;
-                       }
-               }
-
-               internal SourceFile[] Sources {
-                       get {
-                               SourceFile[] retval = new SourceFile [sources.Count];
-                               sources.Values.CopyTo (retval, 0);
+                               ISourceFile[] retval = new ISourceFile [sources.Count];
+                               sources.CopyTo (retval, 0);
                                return retval;
                        }
                }
@@ -248,104 +85,27 @@ namespace Mono.CSharp.Debugger
                // Interface IMonoSymbolWriter
                //
 
-               public MonoSymbolWriter (ModuleBuilder mb)
+               public MonoSymbolWriter (string filename)
                {
-                       this.module_builder = mb;
                        this.methods = new ArrayList ();
-                       this.sources = new Hashtable ();
-                       this.orphant_methods = new ArrayList ();
+                       this.sources = new ArrayList ();
                        this.locals = new ArrayList ();
                        this.file = new MonoSymbolFile ();
-               }
 
-               public void Close ()
-               {
-                       throw new InvalidOperationException ();
-               }
-
-               public byte[] CreateSymbolFile (AssemblyBuilder assembly_builder)
-               {
-                       DoFixups (assembly_builder);
-
-                       return CreateOutput (assembly_builder);
+                       this.filename = filename + ".mdb";
+                       
+                       this.current_method_lines = new LineNumberEntry [50];
                }
 
-               public void CloseNamespace () {
-               }
-
-               // Create and return a new IMonoSymbolDocumentWriter.
-               public ISymbolDocumentWriter DefineDocument (string url,
-                                                            Guid language,
-                                                            Guid languageVendor,
-                                                            Guid documentType)
-               {
-                       if (sources.ContainsKey (url))
-                               return (ISymbolDocumentWriter)sources [url];
-                       SourceFile source_info = new SourceFile (file, url);
-                       sources.Add (url, source_info);
-                       return source_info;
-               }
-
-               public void DefineField (
-                       SymbolToken parent,
-                       string name,
-                       FieldAttributes attributes,
-                       byte[] signature,
-                       SymAddressKind addrKind,
-                       int addr1,
-                       int addr2,
-                       int addr3)
-               {
-                       throw new NotSupportedException ();
-               }
-
-               public void DefineGlobalVariable (
-                       string name,
-                       FieldAttributes attributes,
-                       byte[] signature,
-                       SymAddressKind addrKind,
-                       int addr1,
-                       int addr2,
-                       int addr3)
-               {
-                       throw new NotSupportedException ();
-               }
+               public void CloseNamespace ()
+               { }
 
-               public void DefineLocalVariable (string name,
-                                                FieldAttributes attributes,
-                                                byte[] signature,
-                                                SymAddressKind addrKind,
-                                                int addr1,
-                                                int addr2,
-                                                int addr3,
-                                                int startOffset,
-                                                int endOffset)
+               public void DefineLocalVariable (string name, byte[] signature)
                {
                        if (current_method == null)
                                return;
 
-                       current_method.AddLocal (name, attributes, signature);
-               }
-
-               public void DefineParameter (string name,
-                                            ParameterAttributes attributes,
-                                            int sequence,
-                                            SymAddressKind addrKind,
-                                            int addr1,
-                                            int addr2,
-                                            int addr3)
-               {
-                       throw new NotSupportedException ();
-               }
-
-               public void DefineSequencePoints (ISymbolDocumentWriter document,
-                                                 int[] offsets,
-                                                 int[] lines,
-                                                 int[] columns,
-                                                 int[] endLines,
-                                                 int[] endColumns)
-               {
-                       throw new NotSupportedException ();
+                       current_method.AddLocal (name, signature);
                }
 
                public void MarkSequencePoint (int offset, int line, int column)
@@ -353,64 +113,49 @@ namespace Mono.CSharp.Debugger
                        if (current_method == null)
                                return;
 
-                       LineNumberEntry source_line = new LineNumberEntry (line, offset);
-                       current_method.AddLine (source_line);
-               }
-
-               public void Initialize (IntPtr emitter, string filename, bool fFullBuild)
-               {
-                       throw new NotSupportedException ();
-               }
-
-               public void OpenMethod (SymbolToken symbol_token)
-               {
-                       throw new NotSupportedException ();
-               }
-
-               public void SetMethodSourceRange (ISymbolDocumentWriter startDoc,
-                                                 int startLine, int startColumn,
-                                                 ISymbolDocumentWriter endDoc,
-                                                 int endLine, int endColumn)
-               {
-                       throw new NotSupportedException ();
+                       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 OpenMethod (ISymbolDocumentWriter document, int startLine, int startColumn,
-                                       int endLine, int endColumn, MethodBase method, int namespace_id)
+               public void OpenMethod (ISourceFile file, ISourceMethod method,
+                                       int startRow, int startColumn,
+                                       int endRow, int endColumn)
                {
-                       SourceFile source_info = document as SourceFile;
-
-                       if ((source_info == null) || (method == null))
-                               throw new NullReferenceException ();
-
-                       current_method = new SourceMethod (file, source_info, startLine, startColumn,
-                                                          endLine, endColumn, method, namespace_id);
+                       SourceMethod source = new SourceMethod (
+                               file, method, startRow, startColumn, endRow, endColumn);
 
+                       current_method = source;
                        methods.Add (current_method);
-                       source_info.AddMethod (current_method);
                }
 
                public void CloseMethod ()
                {
+                       current_method.SetLineNumbers (
+                               current_method_lines, current_method_lines_pos);
+                       current_method_lines_pos = 0;
+                       
                        current_method = null;
                }
 
-               public int DefineNamespace (string name, ISymbolDocumentWriter document,
-                                           string[] using_clauses, int parent)
+               public SourceFileEntry DefineDocument (string url)
                {
-                       if ((document == null) || (using_clauses == null))
-                               throw new NullReferenceException ();
-                       if (!(document is SourceFile))
-                               throw new ArgumentException ();
-
-                       SourceFile source_info = (SourceFile) document;
-
-                       return source_info.DefineNamespace (name, using_clauses, parent);
+                       SourceFileEntry entry = new SourceFileEntry (file, url);
+                       sources.Add (entry);
+                       return entry;
                }
 
-               public void OpenNamespace (string name)
+               public int DefineNamespace (string name, SourceFileEntry source,
+                                           string[] using_clauses, int parent)
                {
-                       throw new NotSupportedException ();
+                       if ((source == null) || (using_clauses == null))
+                               throw new NullReferenceException ();
+
+                       return source.DefineNamespace (name, using_clauses, parent);
                }
 
                public int OpenScope (int startOffset)
@@ -430,67 +175,170 @@ namespace Mono.CSharp.Debugger
                        current_method.EndBlock (endOffset);
                }
 
-               public void SetScopeRange (int scopeID, int startOffset, int endOffset)
+               protected byte[] CreateOutput (Guid guid)
                {
-                       throw new NotSupportedException ();
-               }
+                       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)
-               {
-                       throw new NotSupportedException ();
+                       return file.CreateSymbolFile (guid);
                }
 
-               public void SetUnderlyingWriter (IntPtr underlyingWriter)
+               public void WriteSymbolFile (Guid guid)
                {
-                       throw new NotSupportedException ();
+                       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
                {
-                       throw new NotSupportedException ();
-               }
+                       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;
 
-               public void UsingNamespace (string fullName)
-               {
-                       throw new NotSupportedException ();
-               }
+                       private LexicalBlockEntry _implicit_block;
 
-               //
-               // MonoSymbolWriter implementation
-               //
-               protected void DoFixups (Assembly assembly)
-               {
-                       foreach (SourceMethod method in methods) {
-                               if (method._method_base is MethodBuilder) {
-                                       MethodBuilder mb = (MethodBuilder) method._method_base;
-                                       method._token = mb.GetToken ().Token;
-                               } else if (method._method_base is ConstructorBuilder) {
-                                       ConstructorBuilder cb = (ConstructorBuilder) method._method_base;
-                                       method._token = cb.GetToken ().Token;
-                               } else
-                                       throw new NotSupportedException ();
-
-                               if (method.SourceFile == null)
-                                       orphant_methods.Add (method);
+                       public SourceMethod (ISourceFile file, ISourceMethod method,
+                                            int startLine, int startColumn,
+                                            int endLine, int endColumn)
+                       {
+                               this._file = file;
+                               this._method = method;
+
+                               this._start = new LineNumberEntry (startLine, 0);
+                               this._end = new LineNumberEntry (endLine, 0);
+
+                               this._implicit_block = new LexicalBlockEntry (0, 0);
                        }
-               }
 
-               protected byte[] CreateOutput (Assembly assembly)
-               {
-                       foreach (SourceMethod method in Methods) {
-                               if (!method.HasSource) {
-                                       Console.WriteLine ("INGORING METHOD: {0}", method);
-                                       continue;
+                       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);
+                       }
+
+                       public void EndBlock (int endOffset)
+                       {
+                               LexicalBlockEntry block =
+                                       (LexicalBlockEntry) _block_stack.Pop ();
+
+                               block.Close (endOffset);
+                       }
+
+                       public LexicalBlockEntry[] Blocks {
+                               get {
+                                       if (_blocks == null)
+                                               return new LexicalBlockEntry [0];
+                                       else {
+                                               LexicalBlockEntry[] retval =
+                                                       new LexicalBlockEntry [_blocks.Count];
+                                               _blocks.CopyTo (retval, 0);
+                                               return retval;
+                                       }
+                               }
+                       }
+
+                       public LexicalBlockEntry CurrentBlock {
+                               get {
+                                       if ((_block_stack != null) && (_block_stack.Count > 0))
+                                               return (LexicalBlockEntry) _block_stack.Peek ();
+                                       else
+                                               return _implicit_block;
                                }
+                       }
+
+                       public LineNumberEntry[] Lines {
+                               get {
+                                       return lines;
+                               }
+                       }
+
+                       public LocalVariableEntry[] Locals {
+                               get {
+                                       if (_locals == null)
+                                               return new LocalVariableEntry [0];
+                                       else {
+                                               LocalVariableEntry[] retval =
+                                                       new LocalVariableEntry [_locals.Count];
+                                               _locals.CopyTo (retval, 0);
+                                               return retval;
+                                       }
+                               }
+                       }
 
-                               method.SourceFile.DefineMethod (
-                                       method.MethodBase, method.Token, method.Locals,
-                                       method.Lines, method.Blocks, method.Start.Row, method.End.Row,
-                                       method.NamespaceID);
+                       public void AddLocal (string name, byte[] signature)
+                       {
+                               if (_locals == null)
+                                       _locals = new ArrayList ();
+                               _locals.Add (new LocalVariableEntry (
+                                                    name, signature, CurrentBlock.Index));
                        }
 
-                       return file.CreateSymbolFile ();
+                       public ISourceFile SourceFile {
+                               get { return _file; }
+                       }
+
+                       public ISourceMethod Method {
+                               get { return _method; }
+                       }
+
+                       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);
+                       }
                }
        }
 }
-