2004-10-20 Martin Baulig <martin@ximian.com>
[mono.git] / mcs / class / Mono.CSharp.Debugger / MonoSymbolTable.cs
index 436fd1355749dbdc3c9a4a2d8f06077b1e2bf939..4fadaf1e18b467e5411801c0d61b7bc920e55401 100644 (file)
@@ -1,26 +1,80 @@
 //
-// System.Diagnostics.SymbolStore/MonoSymbolTable.cs
+// Mono.CSharp.Debugger/MonoSymbolTable.cs
 //
 // Author:
-//   Martin Baulig (martin@gnome.org)
+//   Martin Baulig (martin@ximian.com)
 //
 // (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.Collections;
 using System.Text;
 using System.IO;
-       
-namespace Mono.CSharp.Debugger
+
+//
+// Parts which are actually written into the symbol file are marked with
+//
+//         #region This is actually written to the symbol file
+//         #endregion
+//
+// Please do not modify these regions without previously talking to me.
+//
+// All changes to the file format must be synchronized in several places:
+//
+// a) The fields in these regions (and their order) must match the actual
+//    contents of the symbol file.
+//
+//    This helps people to understand the symbol file format without reading
+//    too much source code, ie. you look at the appropriate region and then
+//    you know what's actually in the file.
+//
+//    It is also required to help me enforce b).
+//
+// b) The regions must be kept in sync with the unmanaged code in
+//    mono/metadata/debug-mono-symfile.h
+//
+// When making changes to the file format, you must also increase two version
+// numbers:
+//
+// i)  OffsetTable.Version in this file.
+// ii) MONO_SYMBOL_FILE_VERSION in mono/metadata/debug-mono-symfile.h
+//
+// After doing so, recompile everything, including the debugger.  Symbol files
+// with different versions are incompatible to each other and the debugger and
+// the runtime enfore this, so you need to recompile all your assemblies after
+// changing the file format.
+//
+
+namespace Mono.CompilerServices.SymbolWriter
 {
        public struct OffsetTable
        {
-               public const int  Version = 29;
+               public const int  Version = 38;
                public const long Magic   = 0x45e82623fd7fa614;
 
+               #region This is actually written to the symbol file
                public int TotalFileSize;
                public int DataSectionOffset;
                public int DataSectionSize;
@@ -31,6 +85,7 @@ namespace Mono.CSharp.Debugger
                public int MethodTableOffset;
                public int MethodTableSize;
                public int TypeCount;
+               #endregion
 
                internal OffsetTable (BinaryReader reader)
                {
@@ -59,12 +114,23 @@ namespace Mono.CSharp.Debugger
                        bw.Write (MethodTableSize);
                        bw.Write (TypeCount);
                }
+
+               public override string ToString ()
+               {
+                       return String.Format (
+                               "OffsetTable [{0} - {1}:{2} - {3}:{4}:{5} - {6}:{7}:{8} - {9}]",
+                               TotalFileSize, DataSectionOffset, DataSectionSize, SourceCount,
+                               SourceTableOffset, SourceTableSize, MethodCount, MethodTableOffset,
+                               MethodTableSize, TypeCount);
+               }
        }
 
        public struct LineNumberEntry
        {
+               #region This is actually written to the symbol file
                public readonly int Row;
                public readonly int Offset;
+               #endregion
 
                public LineNumberEntry (int row, int offset)
                {
@@ -72,9 +138,7 @@ namespace Mono.CSharp.Debugger
                        this.Offset = offset;
                }
 
-               internal LineNumberEntry (SourceLine line)
-                       : this (line.Row, line.Offset)
-               { }
+               public static LineNumberEntry Null = new LineNumberEntry (0, 0);
 
                internal LineNumberEntry (BinaryReader reader)
                {
@@ -88,122 +152,223 @@ namespace Mono.CSharp.Debugger
                        bw.Write (Offset);
                }
 
+               private class OffsetComparerClass : IComparer
+               {
+                       public int Compare (object a, object b)
+                       {
+                               LineNumberEntry l1 = (LineNumberEntry) a;
+                               LineNumberEntry l2 = (LineNumberEntry) b;
+
+                               if (l1.Offset < l2.Offset)
+                                       return -1;
+                               else if (l1.Offset > l2.Offset)
+                                       return 1;
+                               else
+                                       return 0;
+                       }
+               }
+
+               private class RowComparerClass : IComparer
+               {
+                       public int Compare (object a, object b)
+                       {
+                               LineNumberEntry l1 = (LineNumberEntry) a;
+                               LineNumberEntry l2 = (LineNumberEntry) b;
+
+                               if (l1.Row < l2.Row)
+                                       return -1;
+                               else if (l1.Row > l2.Row)
+                                       return 1;
+                               else
+                                       return 0;
+                       }
+               }
+
+               public static readonly IComparer OffsetComparer = new OffsetComparerClass ();
+               public static readonly IComparer RowComparer = new RowComparerClass ();
+
                public override string ToString ()
                {
                        return String.Format ("[Line {0}:{1}]", Row, Offset);
                }
        }
 
+       public class LexicalBlockEntry
+       {
+               public int Index;
+               #region This is actually written to the symbol file
+               public int StartOffset;
+               public int EndOffset;
+               #endregion
+
+               public LexicalBlockEntry (int index, int start_offset)
+               {
+                       this.Index = index;
+                       this.StartOffset = start_offset;
+               }
+
+               internal LexicalBlockEntry (int index, MyBinaryReader reader)
+               {
+                       this.Index = index;
+                       this.StartOffset = reader.ReadInt32 ();
+                       this.EndOffset = reader.ReadInt32 ();
+               }
+
+               public void Close (int end_offset)
+               {
+                       this.EndOffset = end_offset;
+               }
+
+               internal void Write (MyBinaryWriter bw)
+               {
+                       bw.Write (StartOffset);
+                       bw.Write (EndOffset);
+               }
+
+               public override string ToString ()
+               {
+                       return String.Format ("[LexicalBlock {0}:{1}]", StartOffset, EndOffset);
+               }
+       }
+
        public struct LocalVariableEntry
        {
+               #region This is actually written to the symbol file
                public readonly string Name;
-               public readonly FieldAttributes Attributes;
                public readonly byte[] Signature;
+               public readonly int BlockIndex;
+               #endregion
 
-               public LocalVariableEntry (string Name, FieldAttributes Attributes, byte[] Signature)
+               public LocalVariableEntry (string Name, byte[] Signature, int BlockIndex)
                {
                        this.Name = Name;
-                       this.Attributes = Attributes;
                        this.Signature = Signature;
+                       this.BlockIndex = BlockIndex;
                }
 
-               internal LocalVariableEntry (BinaryReader reader)
+               internal LocalVariableEntry (MyBinaryReader reader)
                {
-                       int name_length = reader.ReadInt32 ();
-                       byte[] name = reader.ReadBytes (name_length);
-                       Name = Encoding.UTF8.GetString (name);
-                       Attributes = (FieldAttributes) reader.ReadInt32 ();
-                       int sig_length = reader.ReadInt32 ();
+                       Name = reader.ReadString ();
+                       int sig_length = reader.ReadLeb128 ();
                        Signature = reader.ReadBytes (sig_length);
+                       BlockIndex = reader.ReadLeb128 ();
                }
 
-               internal void Write (MonoSymbolFile file, BinaryWriter bw)
+               internal void Write (MonoSymbolFile file, MyBinaryWriter bw)
                {
-                       file.WriteString (bw, Name);
-                       bw.Write ((int) Attributes);
-                       bw.Write ((int) Signature.Length);
+                       bw.Write (Name);
+                       bw.WriteLeb128 ((int) Signature.Length);
                        bw.Write (Signature);
+                       bw.WriteLeb128 (BlockIndex);
                }
 
                public override string ToString ()
                {
-                       return String.Format ("[LocalVariable {0}:{1}]", Name, Attributes);
+                       return String.Format ("[LocalVariable {0}]", Name);
                }
        }
 
        public class SourceFileEntry
        {
+               #region This is actually written to the symbol file
+               public readonly int Index;
+               int Count;
+               int NamespaceCount;
+               int NameOffset;
+               int MethodOffset;
+               int NamespaceTableOffset;
+               #endregion
+
                MonoSymbolFile file;
                string file_name;
                ArrayList methods;
-               int index, count, name_offset, method_offset;
+               ArrayList namespaces;
                bool creating;
 
-               internal static int Size {
-                       get { return 16; }
+               public static int Size {
+                       get { return 24; }
                }
 
-               internal SourceFileEntry (MonoSymbolFile file, string file_name, int index)
+               public SourceFileEntry (MonoSymbolFile file, string file_name)
                {
                        this.file = file;
                        this.file_name = file_name;
-                       this.index = index;
+                       this.Index = file.AddSource (this);
 
                        creating = true;
                        methods = new ArrayList ();
+                       namespaces = new ArrayList ();
                }
 
-               public void DefineMethod (MethodBase method, int token, LocalVariableEntry[] locals,
-                                         LineNumberEntry[] lines, int start, int end)
+               public void DefineMethod (string name, int token, LocalVariableEntry[] locals,
+                                         LineNumberEntry[] lines, LexicalBlockEntry[] blocks,
+                                         int start, int end, int namespace_id)
                {
                        if (!creating)
                                throw new InvalidOperationException ();
 
                        MethodEntry entry = new MethodEntry (
-                               file, this, method, token, locals, lines, start, end);
+                               file, this, name, (int) token, locals, lines, blocks,
+                               start, end, namespace_id);
 
                        methods.Add (entry);
                        file.AddMethod (entry);
                }
 
-               internal void WriteData (BinaryWriter bw)
+               public int DefineNamespace (string name, string[] using_clauses, int parent)
                {
-                       name_offset = (int) bw.BaseStream.Position;
-                       file.WriteString (bw, file_name);
+                       if (!creating)
+                               throw new InvalidOperationException ();
+
+                       int index = file.GetNextNamespaceIndex ();
+                       NamespaceEntry ns = new NamespaceEntry (name, index, using_clauses, parent);
+                       namespaces.Add (ns);
+                       return index;
+               }
+
+               internal void WriteData (MyBinaryWriter bw)
+               {
+                       NameOffset = (int) bw.BaseStream.Position;
+                       bw.Write (file_name);
 
                        ArrayList list = new ArrayList ();
                        foreach (MethodEntry entry in methods)
                                list.Add (entry.Write (file, bw));
                        list.Sort ();
-                       count = list.Count;
+                       Count = list.Count;
 
-                       method_offset = (int) bw.BaseStream.Position;
+                       MethodOffset = (int) bw.BaseStream.Position;
                        foreach (MethodSourceEntry method in list)
                                method.Write (bw);
+
+                       NamespaceCount = namespaces.Count;
+                       NamespaceTableOffset = (int) bw.BaseStream.Position;
+                       foreach (NamespaceEntry ns in namespaces)
+                               ns.Write (file, bw);
                }
 
                internal void Write (BinaryWriter bw)
                {
-                       bw.Write (index);
-                       bw.Write (count);
-                       bw.Write (name_offset);
-                       bw.Write (method_offset);
+                       bw.Write (Index);
+                       bw.Write (Count);
+                       bw.Write (NamespaceCount);
+                       bw.Write (NameOffset);
+                       bw.Write (MethodOffset);
+                       bw.Write (NamespaceTableOffset);
                }
 
                internal SourceFileEntry (MonoSymbolFile file, BinaryReader reader)
                {
                        this.file = file;
 
-                       index = reader.ReadInt32 ();
-                       count = reader.ReadInt32 ();
-                       name_offset = reader.ReadInt32 ();
-                       method_offset = reader.ReadInt32 ();
-
-                       file_name = file.ReadString (name_offset);
-               }
+                       Index = reader.ReadInt32 ();
+                       Count = reader.ReadInt32 ();
+                       NamespaceCount = reader.ReadInt32 ();
+                       NameOffset = reader.ReadInt32 ();
+                       MethodOffset = reader.ReadInt32 ();
+                       NamespaceTableOffset = reader.ReadInt32 ();
 
-               public int Index {
-                       get { return index; }
+                       file_name = file.ReadString (NameOffset);
                }
 
                public string FileName {
@@ -218,13 +383,33 @@ namespace Mono.CSharp.Debugger
                                BinaryReader reader = file.BinaryReader;
                                int old_pos = (int) reader.BaseStream.Position;
 
-                               reader.BaseStream.Position = method_offset;
+                               reader.BaseStream.Position = MethodOffset;
                                ArrayList list = new ArrayList ();
-                               for (int i = 0; i < count; i ++)
+                               for (int i = 0; i < Count; i ++)
                                        list.Add (new MethodSourceEntry (reader));
                                reader.BaseStream.Position = old_pos;
 
-                               MethodSourceEntry[] retval = new MethodSourceEntry [count];
+                               MethodSourceEntry[] retval = new MethodSourceEntry [Count];
+                               list.CopyTo (retval, 0);
+                               return retval;
+                       }
+               }
+
+               public NamespaceEntry[] Namespaces {
+                       get {
+                               if (creating)
+                                       throw new InvalidOperationException ();
+
+                               MyBinaryReader reader = file.BinaryReader;
+                               int old_pos = (int) reader.BaseStream.Position;
+
+                               reader.BaseStream.Position = NamespaceTableOffset;
+                               ArrayList list = new ArrayList ();
+                               for (int i = 0; i < NamespaceCount; i ++)
+                                       list.Add (new NamespaceEntry (file, reader));
+                               reader.BaseStream.Position = old_pos;
+
+                               NamespaceEntry[] retval = new NamespaceEntry [list.Count];
                                list.CopyTo (retval, 0);
                                return retval;
                        }
@@ -232,16 +417,19 @@ namespace Mono.CSharp.Debugger
 
                public override string ToString ()
                {
-                       return String.Format ("SourceFileEntry ({0}:{1}:{2})", index, file_name, count);
+                       return String.Format ("SourceFileEntry ({0}:{1}:{2})",
+                                             Index, file_name, Count);
                }
        }
 
        public struct MethodSourceEntry : IComparable
        {
+               #region This is actually written to the symbol file
                public readonly int Index;
                public readonly int FileOffset;
                public readonly int StartRow;
                public readonly int EndRow;
+               #endregion
 
                public MethodSourceEntry (int index, int file_offset, int start, int end)
                {
@@ -259,11 +447,8 @@ namespace Mono.CSharp.Debugger
                        EndRow = reader.ReadInt32 ();
                }
 
-               public static int Size
-               {
-                       get {
-                               return 16;
-                       }
+               public static int Size {
+                       get { return 16; }
                }
 
                internal void Write (BinaryWriter bw)
@@ -293,69 +478,100 @@ namespace Mono.CSharp.Debugger
                }
        }
 
-       public class MethodEntry
+       public struct MethodIndexEntry
+       {
+               #region This is actually written to the symbol file
+               public readonly int FileOffset;
+               public readonly int Token;
+               #endregion
+
+               public static int Size {
+                       get { return 8; }
+               }
+
+               public MethodIndexEntry (int offset, int token)
+               {
+                       this.FileOffset = offset;
+                       this.Token = token;
+               }
+
+               internal MethodIndexEntry (BinaryReader reader)
+               {
+                       FileOffset = reader.ReadInt32 ();
+                       Token = reader.ReadInt32 ();
+               }
+
+               internal void Write (BinaryWriter bw)
+               {
+                       bw.Write (FileOffset);
+                       bw.Write (Token);
+               }
+
+               public override string ToString ()
+               {
+                       return String.Format ("MethodIndexEntry ({0}:{1:x})",
+                                             FileOffset, Token);
+               }
+       }
+
+       public class MethodEntry : IComparable
        {
                #region This is actually written to the symbol file
                public readonly int SourceFileIndex;
                public readonly int Token;
                public readonly int StartRow;
                public readonly int EndRow;
-               public readonly int ThisTypeIndex;
-               public readonly int NumParameters;
                public readonly int NumLocals;
                public readonly int NumLineNumbers;
+               public readonly int NamespaceID;
+               public readonly bool LocalNamesAmbiguous;
 
                int NameOffset;
-               int FullNameOffset;
                int TypeIndexTableOffset;
                int LocalVariableTableOffset;
                int LineNumberTableOffset;
+               int NumLexicalBlocks;
+               int LexicalBlockTableOffset;
                #endregion
 
                int index;
                int file_offset;
-               string name;
-               string full_name;
 
                public readonly SourceFileEntry SourceFile;
                public readonly LineNumberEntry[] LineNumbers;
-               public readonly int[] ParamTypeIndices;
                public readonly int[] LocalTypeIndices;
                public readonly LocalVariableEntry[] Locals;
+               public readonly LexicalBlockEntry[] LexicalBlocks;
 
-               public static int Size
-               {
-                       get {
-                               return 48;
-                       }
-               }
+               public readonly MonoSymbolFile SymbolFile;
 
-               public string Name {
-                       get { return name; }
+               public int Index {
+                       get { return index; }
+                       set { index = value; }
                }
 
-               public string FullName {
-                       get { return full_name; }
+               public static int Size {
+                       get { return 52; }
                }
 
-               internal MethodEntry (MonoSymbolFile file, BinaryReader reader)
+               internal MethodEntry (MonoSymbolFile file, MyBinaryReader reader, int index)
                {
+                       this.SymbolFile = file;
+                       this.index = index;
                        SourceFileIndex = reader.ReadInt32 ();
                        Token = reader.ReadInt32 ();
                        StartRow = reader.ReadInt32 ();
                        EndRow = reader.ReadInt32 ();
-                       ThisTypeIndex = reader.ReadInt32 ();
-                       NumParameters = reader.ReadInt32 ();
                        NumLocals = reader.ReadInt32 ();
                        NumLineNumbers = reader.ReadInt32 ();
                        NameOffset = reader.ReadInt32 ();
-                       FullNameOffset = reader.ReadInt32 ();
                        TypeIndexTableOffset = reader.ReadInt32 ();
                        LocalVariableTableOffset = reader.ReadInt32 ();
                        LineNumberTableOffset = reader.ReadInt32 ();
-
-                       name = file.ReadString (NameOffset);
-                       full_name = file.ReadString (FullNameOffset);
+                       NumLexicalBlocks = reader.ReadInt32 ();
+                       LexicalBlockTableOffset = reader.ReadInt32 ();
+                       NamespaceID = reader.ReadInt32 ();
+                       LocalNamesAmbiguous = reader.ReadInt32 () != 0;
 
                        SourceFile = file.GetSourceFile (SourceFileIndex);
 
@@ -387,125 +603,245 @@ namespace Mono.CSharp.Debugger
                                long old_pos = reader.BaseStream.Position;
                                reader.BaseStream.Position = TypeIndexTableOffset;
 
-                               ParamTypeIndices = new int [NumParameters];
                                LocalTypeIndices = new int [NumLocals];
 
-                               for (int i = 0; i < NumParameters; i++)
-                                       ParamTypeIndices [i] = reader.ReadInt32 ();
                                for (int i = 0; i < NumLocals; i++)
                                        LocalTypeIndices [i] = reader.ReadInt32 ();
 
                                reader.BaseStream.Position = old_pos;
                        }
+
+                       if (LexicalBlockTableOffset != 0) {
+                               long old_pos = reader.BaseStream.Position;
+                               reader.BaseStream.Position = LexicalBlockTableOffset;
+
+                               LexicalBlocks = new LexicalBlockEntry [NumLexicalBlocks];
+                               for (int i = 0; i < NumLexicalBlocks; i++)
+                                       LexicalBlocks [i] = new LexicalBlockEntry (i, reader);
+
+                               reader.BaseStream.Position = old_pos;
+                       }
                }
 
-               internal MethodEntry (MonoSymbolFile file, SourceFileEntry source, MethodBase method,
-                                     int token, LocalVariableEntry[] locals, LineNumberEntry[] lines,
-                                     int start_row, int end_row)
+               internal MethodEntry (MonoSymbolFile file, SourceFileEntry source,
+                                     string name, int token, LocalVariableEntry[] locals,
+                                     LineNumberEntry[] lines, LexicalBlockEntry[] blocks,
+                                     int start_row, int end_row, int namespace_id)
                {
-                       index = file.GetNextMethodIndex ();
+                       this.SymbolFile = file;
+
+                       index = -1;
 
                        Token = token;
                        SourceFileIndex = source.Index;
                        SourceFile = source;
                        StartRow = start_row;
                        EndRow = end_row;
+                       NamespaceID = namespace_id;
+                       LexicalBlocks = blocks;
+                       NumLexicalBlocks = LexicalBlocks != null ? LexicalBlocks.Length : 0;
 
-                       NumLineNumbers = lines.Length;
-                       LineNumbers = lines;
-
-                       ParameterInfo[] parameters = method.GetParameters ();
-                       if (parameters == null)
-                               parameters = new ParameterInfo [0];
-
-                       StringBuilder sb = new StringBuilder ();
-                       sb.Append (method.DeclaringType.FullName);
-                       sb.Append (".");
-                       sb.Append (method.Name);
-                       sb.Append ("(");
-                       for (int i = 0; i < parameters.Length; i++) {
-                               if (i > 0)
-                                       sb.Append (",");
-                               sb.Append (parameters [i].ParameterType.FullName);
-                       }
-                       sb.Append (")");
-
-                       name = method.Name;
-                       full_name = sb.ToString ();
+                       LineNumbers = BuildLineNumberTable (lines);
+                       NumLineNumbers = LineNumbers.Length;
 
-                       NumParameters = parameters.Length;
-                       ParamTypeIndices = new int [NumParameters];
-                       for (int i = 0; i < NumParameters; i++)
-                               ParamTypeIndices [i] = file.DefineType (parameters [i].ParameterType);
+                       file.NumLineNumbers += NumLineNumbers;
 
-                       NumLocals = locals.Length;
+                       NumLocals = locals != null ? locals.Length : 0;
                        Locals = locals;
 
+                       if (NumLocals <= 32) {
+                               // Most of the time, the O(n^2) factor is actually
+                               // less than the cost of allocating the hash table,
+                               // 32 is a rough number obtained through some testing.
+                               
+                               for (int i = 0; i < NumLocals; i ++) {
+                                       string nm = locals [i].Name;
+                                       
+                                       for (int j = i + 1; j < NumLocals; j ++) {
+                                               if (locals [j].Name == nm) {
+                                                       LocalNamesAmbiguous = true;
+                                                       goto locals_check_done;
+                                               }
+                                       }
+                               }
+                       locals_check_done :
+                               ;
+                       } else {
+                               Hashtable local_names = new Hashtable ();
+                               foreach (LocalVariableEntry local in locals) {
+                                       if (local_names.Contains (local.Name)) {
+                                               LocalNamesAmbiguous = true;
+                                               break;
+                                       }
+                                       local_names.Add (local.Name, local);
+                               }
+                       }
+
                        LocalTypeIndices = new int [NumLocals];
                        for (int i = 0; i < NumLocals; i++)
                                LocalTypeIndices [i] = file.GetNextTypeIndex ();
+               }
+               
+               static LineNumberEntry [] tmp_buff = new LineNumberEntry [20];
+
+               // BuildLineNumberTable() eliminates duplicate line numbers and ensures
+               // we aren't going "backwards" since this would counfuse the runtime's
+               // debugging code (and the debugger).
+               //
+               // In the line number table, the "offset" field most be strictly
+               // monotonic increasing; that is, the next entry must not have an offset
+               // which is equal to or less than the current one.
+               //
+               // The most common case is that our input (ie. the line number table as
+               // we get it from mcs) contains several entries with the same offset
+               // (and different line numbers) - but it may also happen that the offset
+               // is decreasing (this can be considered as an exception, such lines will
+               // simply be discarded).
+               LineNumberEntry[] BuildLineNumberTable (LineNumberEntry[] line_numbers)
+               {
+                       int pos = 0;
+                       int last_offset = -1;
+                       int last_row = -1;
+
+                       if (line_numbers == null)
+                               return new LineNumberEntry [0];
+                       
+                       if (tmp_buff.Length < (line_numbers.Length + 1))
+                               tmp_buff = new LineNumberEntry [(line_numbers.Length + 1) * 2];
+
+                       for (int i = 0; i < line_numbers.Length; i++) {
+                               LineNumberEntry line = line_numbers [i];
+
+                               if (line.Offset > last_offset) {
+                                       if (last_row >= 0)
+                                               tmp_buff [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;
+                               }
+                       }
 
-                       if (method.IsStatic)
-                               ThisTypeIndex = 0;
-                       else
-                               ThisTypeIndex = file.DefineType (method.ReflectedType);
+                       if (last_row >= 0)
+                               tmp_buff [pos ++] = new LineNumberEntry (last_row, last_offset);
+
+                       LineNumberEntry [] retval = new LineNumberEntry [pos];
+                       Array.Copy (tmp_buff, retval, pos);
+                       return retval;
                }
 
-               internal MethodSourceEntry Write (MonoSymbolFile file, BinaryWriter bw)
+               internal MethodSourceEntry Write (MonoSymbolFile file, MyBinaryWriter bw)
                {
-                       NameOffset = (int) bw.BaseStream.Position;
-                       file.WriteString (bw, name);
+                       if (index <= 0)
+                               throw new InvalidOperationException ();
 
-                       FullNameOffset = (int) bw.BaseStream.Position;
-                       file.WriteString (bw, full_name);
+                       NameOffset = (int) bw.BaseStream.Position;
 
                        TypeIndexTableOffset = (int) bw.BaseStream.Position;
 
-                       for (int i = 0; i < NumParameters; i++)
-                               bw.Write (ParamTypeIndices [i]);
                        for (int i = 0; i < NumLocals; i++)
                                bw.Write (LocalTypeIndices [i]);
 
                        LocalVariableTableOffset = (int) bw.BaseStream.Position;
-
                        for (int i = 0; i < NumLocals; i++)
                                Locals [i].Write (file, bw);
+                       file.LocalCount += NumLocals;
 
                        LineNumberTableOffset = (int) bw.BaseStream.Position;
-
                        for (int i = 0; i < NumLineNumbers; i++)
                                LineNumbers [i].Write (bw);
+                       file.LineNumberCount += NumLineNumbers;
 
+                       LexicalBlockTableOffset = (int) bw.BaseStream.Position;
+                       for (int i = 0; i < NumLexicalBlocks; i++)
+                               LexicalBlocks [i].Write (bw);
                        file_offset = (int) bw.BaseStream.Position;
 
                        bw.Write (SourceFileIndex);
                        bw.Write (Token);
                        bw.Write (StartRow);
                        bw.Write (EndRow);
-                       bw.Write (ThisTypeIndex);
-                       bw.Write (NumParameters);
                        bw.Write (NumLocals);
                        bw.Write (NumLineNumbers);
                        bw.Write (NameOffset);
-                       bw.Write (FullNameOffset);
                        bw.Write (TypeIndexTableOffset);
                        bw.Write (LocalVariableTableOffset);
                        bw.Write (LineNumberTableOffset);
+                       bw.Write (NumLexicalBlocks);
+                       bw.Write (LexicalBlockTableOffset);
+                       bw.Write (NamespaceID);
+                       bw.Write (LocalNamesAmbiguous ? 1 : 0);
 
                        return new MethodSourceEntry (index, file_offset, StartRow, EndRow);
                }
 
                internal void WriteIndex (BinaryWriter bw)
                {
-                       bw.Write (file_offset);
-                       bw.Write (FullNameOffset);
+                       new MethodIndexEntry (file_offset, Token).Write (bw);
+               }
+
+               public int CompareTo (object obj)
+               {
+                       MethodEntry method = (MethodEntry) obj;
+
+                       if (method.Token < Token)
+                               return 1;
+                       else if (method.Token > Token)
+                               return -1;
+                       else
+                               return 0;
+               }
+
+               public override string ToString ()
+               {
+                       return String.Format ("[Method {0}:{1}:{2}:{3}:{4} - {6}:{7} - {5}]",
+                                             index, Token, SourceFileIndex, StartRow, EndRow,
+                                             SourceFile, NumLocals, NumLineNumbers);
+               }
+       }
+
+       public struct NamespaceEntry
+       {
+               #region This is actually written to the symbol file
+               public readonly string Name;
+               public readonly int Index;
+               public readonly int Parent;
+               public readonly string[] UsingClauses;
+               #endregion
+
+               public NamespaceEntry (string name, int index, string[] using_clauses, int parent)
+               {
+                       this.Name = name;
+                       this.Index = index;
+                       this.Parent = parent;
+                       this.UsingClauses = using_clauses != null ? using_clauses : new string [0];
+               }
+
+               internal NamespaceEntry (MonoSymbolFile file, MyBinaryReader reader)
+               {
+                       Name = reader.ReadString ();
+                       Index = reader.ReadLeb128 ();
+                       Parent = reader.ReadLeb128 ();
+
+                       int count = reader.ReadLeb128 ();
+                       UsingClauses = new string [count];
+                       for (int i = 0; i < count; i++)
+                               UsingClauses [i] = reader.ReadString ();
+               }
+
+               internal void Write (MonoSymbolFile file, MyBinaryWriter bw)
+               {
+                       bw.Write (Name);
+                       bw.WriteLeb128 (Index);
+                       bw.WriteLeb128 (Parent);
+                       bw.WriteLeb128 (UsingClauses.Length);
+                       foreach (string uc in UsingClauses)
+                               bw.Write (uc);
                }
 
                public override string ToString ()
                {
-                       return String.Format ("[Method {0}:{1}:{2}:{3}:{4} - {5} - {6}]",
-                                             SourceFileIndex, index, Token, StartRow, EndRow,
-                                             SourceFile, FullName);
+                       return String.Format ("[Namespace {0}:{1}:{2}]", Name, Index, Parent);
                }
        }
 }