Merge pull request #1024 from ludovic-henry/pr10-proflog-counters
[mono.git] / mcs / class / Mono.CompilerServices.SymbolWriter / MonoSymbolTable.cs
index 65b5998bf12c775cd017a0c4775340b6798bf3b0..277f25a7f6fade9f356f88b0795e82941db80e57 100644 (file)
@@ -30,7 +30,7 @@
 
 using System;
 using System.Security.Cryptography;
-using System.Collections;
+using System.Collections.Generic;
 using System.Text;
 using System.IO;
 
@@ -183,63 +183,56 @@ namespace Mono.CompilerServices.SymbolWriter
        {
                #region This is actually written to the symbol file
                public readonly int Row;
+               public int Column;
+               public int EndRow, EndColumn;
                public readonly int File;
                public readonly int Offset;
-               public readonly bool IsHidden;
+               public readonly bool IsHidden;  // Obsolete is never used
                #endregion
 
-               public LineNumberEntry (int file, int row, int offset)
-                       : this (file, row, offset, false)
-               { }
-
-               public LineNumberEntry (int file, int row, int offset, bool is_hidden)
+               public sealed class LocationComparer : IComparer<LineNumberEntry>
                {
-                       this.File = file;
-                       this.Row = row;
-                       this.Offset = offset;
-                       this.IsHidden = is_hidden;
+                       public static readonly LocationComparer Default = new LocationComparer ();
+
+                       public int Compare (LineNumberEntry l1, LineNumberEntry l2)
+                       {
+                               return l1.Row == l2.Row ?
+                                       l1.Column.CompareTo (l2.Column) :
+                                       l1.Row.CompareTo (l2.Row);
+                       }
                }
 
-               public static LineNumberEntry Null = new LineNumberEntry (0, 0, 0);
+               public static readonly LineNumberEntry Null = new LineNumberEntry (0, 0, 0, 0);
 
-               private class OffsetComparerClass : IComparer
+               public LineNumberEntry (int file, int row, int column, int offset)
+                       : this (file, row, offset, column, false)
                {
-                       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 LineNumberEntry (int file, int row, int offset)
+                       : this (file, row, -1, offset, false)
+               {
+               }
+
+               public LineNumberEntry (int file, int row, int column, int offset, bool is_hidden)
+               : this (file, row, column, -1, -1, offset, is_hidden)
                {
-                       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 LineNumberEntry (int file, int row, int column, int end_row, int end_column, int offset, bool is_hidden)
+               {
+                       this.File = file;
+                       this.Row = row;
+                       this.Column = column;
+                       this.EndRow = end_row;
+                       this.EndColumn = end_column;
+                       this.Offset = offset;
+                       this.IsHidden = is_hidden;
+               }
 
                public override string ToString ()
                {
-                       return String.Format ("[Line {0}:{1}:{2}]", File, Row, Offset);
+                       return String.Format ("[Line {0}:{1,2}-{3,4}:{5}]", File, Row, Column, EndRow, EndColumn, Offset);
                }
        }
 
@@ -336,7 +329,7 @@ namespace Mono.CompilerServices.SymbolWriter
                public override string ToString ()
                {
                        return String.Format ("[LocalVariable {0}:{1}:{2}]",
-                                             Name, Index, BlockIndex);
+                                             Name, Index, BlockIndex - 1);
                }
        }
 
@@ -453,8 +446,8 @@ namespace Mono.CompilerServices.SymbolWriter
                public readonly int ID;
                #endregion
 
-               ArrayList captured_vars = new ArrayList ();
-               ArrayList captured_scopes = new ArrayList ();
+               List<CapturedVariable> captured_vars = new List<CapturedVariable> ();
+               List<CapturedScope> captured_scopes = new List<CapturedScope> ();
 
                public AnonymousScopeEntry (int id)
                {
@@ -529,8 +522,8 @@ namespace Mono.CompilerServices.SymbolWriter
 
                MonoSymbolFile file;
                SourceFileEntry source;
-               ArrayList include_files;
-               ArrayList namespaces;
+               List<SourceFileEntry> include_files;
+               List<NamespaceEntry> namespaces;
 
                bool creating;
 
@@ -550,7 +543,7 @@ namespace Mono.CompilerServices.SymbolWriter
                        this.Index = file.AddCompileUnit (this);
 
                        creating = true;
-                       namespaces = new ArrayList ();
+                       namespaces = new List<NamespaceEntry> ();
                }
 
                public void AddFile (SourceFileEntry file)
@@ -559,7 +552,7 @@ namespace Mono.CompilerServices.SymbolWriter
                                throw new InvalidOperationException ();
 
                        if (include_files == null)
-                               include_files = new ArrayList ();
+                               include_files = new List<SourceFileEntry> ();
 
                        include_files.Add (file);
                }
@@ -616,6 +609,11 @@ namespace Mono.CompilerServices.SymbolWriter
                        DataOffset = reader.ReadInt32 ();
                }
 
+               public void ReadAll ()
+               {
+                       ReadData ();
+               }
+
                void ReadData ()
                {
                        if (creating)
@@ -635,15 +633,13 @@ namespace Mono.CompilerServices.SymbolWriter
 
                                int count_includes = reader.ReadLeb128 ();
                                if (count_includes > 0) {
-                                       include_files = new ArrayList ();
-                                       for (int i = 0; i < count_includes; i++) {
-                                               // FIXME: The debugger will need this later on.
-                                               reader.ReadLeb128 ();
-                                       }
+                                       include_files = new List<SourceFileEntry> ();
+                                       for (int i = 0; i < count_includes; i++)
+                                               include_files.Add (file.GetSourceFile (reader.ReadLeb128 ()));
                                }
 
                                int count_ns = reader.ReadLeb128 ();
-                               namespaces = new ArrayList ();
+                               namespaces = new List<NamespaceEntry> ();
                                for (int i = 0; i < count_ns; i ++)
                                        namespaces.Add (new NamespaceEntry (file, reader));
 
@@ -659,6 +655,18 @@ namespace Mono.CompilerServices.SymbolWriter
                                return retval;
                        }
                }
+
+               public SourceFileEntry[] IncludeFiles {
+                       get {
+                               ReadData ();
+                               if (include_files == null)
+                                       return new SourceFileEntry [0];
+
+                               SourceFileEntry[] retval = new SourceFileEntry [include_files.Count];
+                               include_files.CopyTo (retval, 0);
+                               return retval;
+                       }
+               }
        }
 
        public class SourceFileEntry
@@ -688,26 +696,33 @@ namespace Mono.CompilerServices.SymbolWriter
                        creating = true;
                }
 
-               public SourceFileEntry (MonoSymbolFile file, string file_name,
-                                       byte[] guid, byte[] checksum)
+               public SourceFileEntry (MonoSymbolFile file, string file_name, byte[] guid, byte[] checksum)
                        : this (file, file_name)
                {
                        this.guid = guid;
                        this.hash = checksum;
                }
 
+               public byte[] Checksum {
+                       get {
+                               return hash;
+                       }
+               }
+
                internal void WriteData (MyBinaryWriter bw)
                {
                        DataOffset = (int) bw.BaseStream.Position;
                        bw.Write (file_name);
 
-                       if (guid == null) {
-                               guid = Guid.NewGuid ().ToByteArray ();
+                       if (guid == null)
+                               guid = new byte[16];
+
+                       if (hash == null) {
                                try {
-                                       using (FileStream fs = new FileStream (file_name, FileMode.Open, FileAccess.Read)) {
-                                               MD5 md5 = MD5.Create ();
-                                               hash = md5.ComputeHash (fs);
-                                       }
+                                   using (FileStream fs = new FileStream (file_name, FileMode.Open, FileAccess.Read)) {
+                                       MD5 md5 = MD5.Create ();
+                                       hash = md5.ComputeHash (fs);
+                                   }
                                } catch {
                                        hash = new byte [16];
                                }
@@ -744,6 +759,7 @@ namespace Mono.CompilerServices.SymbolWriter
 
                public string FileName {
                        get { return file_name; }
+                       set { file_name = value; }
                }
 
                public bool AutoGenerated {
@@ -798,7 +814,6 @@ namespace Mono.CompilerServices.SymbolWriter
                public const int Default_LineRange = 8;
                public const byte Default_OpcodeBase = 9;
 
-               public const bool SuppressDuplicates = true;
 #endregion
 
                public const byte DW_LNS_copy = 1;
@@ -812,6 +827,9 @@ namespace Mono.CompilerServices.SymbolWriter
                // MONO extensions.
                public const byte DW_LNE_MONO_negate_is_hidden = 0x40;
 
+               internal const byte DW_LNE_MONO__extensions_start = 0x40;
+               internal const byte DW_LNE_MONO__extensions_end   = 0x7f;
+
                protected LineNumberTable (MonoSymbolFile file)
                {
                        this.LineBase = file.OffsetTable.LineNumberTable_LineBase;
@@ -826,7 +844,7 @@ namespace Mono.CompilerServices.SymbolWriter
                        this._line_numbers = lines;
                }
 
-               internal void Write (MonoSymbolFile file, MyBinaryWriter bw)
+               internal void Write (MonoSymbolFile file, MyBinaryWriter bw, bool hasColumnsInfo, bool hasEndInfo)
                {
                        int start = (int) bw.BaseStream.Position;
 
@@ -836,11 +854,6 @@ namespace Mono.CompilerServices.SymbolWriter
                                int line_inc = LineNumbers [i].Row - last_line;
                                int offset_inc = LineNumbers [i].Offset - last_offset;
 
-                               if (SuppressDuplicates && (i+1 < LineNumbers.Length)) {
-                                       if (LineNumbers [i+1].Equals (LineNumbers [i]))
-                                               continue;
-                               }
-
                                if (LineNumbers [i].File != last_file) {
                                        bw.Write (DW_LNS_set_file);
                                        bw.WriteLeb128 (LineNumbers [i].File);
@@ -888,19 +901,39 @@ namespace Mono.CompilerServices.SymbolWriter
                        bw.Write ((byte) 1);
                        bw.Write (DW_LNE_end_sequence);
 
+                       if (hasColumnsInfo) {
+                               for (int i = 0; i < LineNumbers.Length; i++) {
+                                       var ln = LineNumbers [i];
+                                       if (ln.Row >= 0)
+                                               bw.WriteLeb128 (ln.Column);
+                               }
+                       }
+
+                       if (hasEndInfo) {
+                               for (int i = 0; i < LineNumbers.Length; i++) {
+                                       var ln = LineNumbers [i];
+                                       if (ln.EndRow == -1 || ln.EndColumn == -1 || ln.Row > ln.EndRow) {
+                                               bw.WriteLeb128 (0xffffff);
+                                       } else {
+                                               bw.WriteLeb128 (ln.EndRow - ln.Row);
+                                               bw.WriteLeb128 (ln.EndColumn);
+                                       }
+                               }
+                       }
+
                        file.ExtendedLineNumberSize += (int) bw.BaseStream.Position - start;
                }
 
-               internal static LineNumberTable Read (MonoSymbolFile file, MyBinaryReader br)
+               internal static LineNumberTable Read (MonoSymbolFile file, MyBinaryReader br, bool readColumnsInfo, bool readEndInfo)
                {
                        LineNumberTable lnt = new LineNumberTable (file);
-                       lnt.DoRead (file, br);
+                       lnt.DoRead (file, br, readColumnsInfo, readEndInfo);
                        return lnt;
                }
 
-               void DoRead (MonoSymbolFile file, MyBinaryReader br)
+               void DoRead (MonoSymbolFile file, MyBinaryReader br, bool includesColumns, bool includesEnds)
                {
-                       ArrayList lines = new ArrayList ();
+                       var lines = new List<LineNumberEntry> ();
 
                        bool is_hidden = false, modified = false;
                        int stm_line = 1, stm_offset = 0, stm_file = 1;
@@ -915,15 +948,17 @@ namespace Mono.CompilerServices.SymbolWriter
                                        if (opcode == DW_LNE_end_sequence) {
                                                if (modified)
                                                        lines.Add (new LineNumberEntry (
-                                                               stm_file, stm_line, stm_offset, is_hidden));
+                                                               stm_file, stm_line, -1, stm_offset, is_hidden));
                                                break;
                                        } else if (opcode == DW_LNE_MONO_negate_is_hidden) {
                                                is_hidden = !is_hidden;
                                                modified = true;
-                                       } else
-                                               throw new MonoSymbolFileException (
-                                                       "Unknown extended opcode {0:x} in LNT ({1})",
-                                                       opcode, file.FileName);
+                                       } else if ((opcode >= DW_LNE_MONO__extensions_start) &&
+                                                  (opcode <= DW_LNE_MONO__extensions_end)) {
+                                               ; // reserved for future extensions
+                                       } else {
+                                               throw new MonoSymbolFileException ("Unknown extended opcode {0:x}", opcode);
+                                       }
 
                                        br.BaseStream.Position = end_pos;
                                        continue;
@@ -931,7 +966,7 @@ namespace Mono.CompilerServices.SymbolWriter
                                        switch (opcode) {
                                        case DW_LNS_copy:
                                                lines.Add (new LineNumberEntry (
-                                                       stm_file, stm_line, stm_offset, is_hidden));
+                                                       stm_file, stm_line, -1, stm_offset, is_hidden));
                                                modified = false;
                                                break;
                                        case DW_LNS_advance_pc:
@@ -961,13 +996,34 @@ namespace Mono.CompilerServices.SymbolWriter
                                        stm_offset += opcode / LineRange;
                                        stm_line += LineBase + (opcode % LineRange);
                                        lines.Add (new LineNumberEntry (
-                                               stm_file, stm_line, stm_offset, is_hidden));
+                                               stm_file, stm_line, -1, stm_offset, is_hidden));
                                        modified = false;
                                }
                        }
 
-                       _line_numbers = new LineNumberEntry [lines.Count];
-                       lines.CopyTo (_line_numbers, 0);
+                       _line_numbers = lines.ToArray ();
+
+                       if (includesColumns) {
+                               for (int i = 0; i < _line_numbers.Length; ++i) {
+                                       var ln = _line_numbers[i];
+                                       if (ln.Row >= 0)
+                                               ln.Column = br.ReadLeb128 ();
+                               }
+                       }
+                       if (includesEnds) {
+                               for (int i = 0; i < _line_numbers.Length; ++i) {
+                                       var ln = _line_numbers[i];
+
+                                       int row = br.ReadLeb128 ();
+                                       if (row == 0xffffff) {
+                                               ln.EndRow = -1;
+                                               ln.EndColumn = -1;
+                                       } else {
+                                               ln.EndRow = ln.Row + row;
+                                               ln.EndColumn = br.ReadLeb128 ();
+                                       }
+                               }
+                       }
                }
 
                public bool GetMethodBounds (out LineNumberEntry start, out LineNumberEntry end)
@@ -1024,7 +1080,9 @@ namespace Mono.CompilerServices.SymbolWriter
                [Flags]
                public enum Flags
                {
-                       LocalNamesAmbiguous     = 1
+                       LocalNamesAmbiguous     = 1,
+                       ColumnsInfoIncluded = 1 << 1,
+                       EndInfoIncluded = 1 << 2
                }
 
                public const int Size = 12;
@@ -1101,9 +1159,9 @@ namespace Mono.CompilerServices.SymbolWriter
                        locals_check_done :
                                ;
                        } else {
-                               Hashtable local_names = new Hashtable ();
+                               var local_names = new Dictionary<string, LocalVariableEntry> ();
                                foreach (LocalVariableEntry local in locals) {
-                                       if (local_names.Contains (local.Name)) {
+                                       if (local_names.ContainsKey (local.Name)) {
                                                flags |= Flags.LocalNamesAmbiguous;
                                                break;
                                        }
@@ -1112,7 +1170,7 @@ namespace Mono.CompilerServices.SymbolWriter
                        }
                }
                
-               void CheckLineNumberTable (LineNumberEntry[] line_numbers)
+               static void CheckLineNumberTable (LineNumberEntry[] line_numbers)
                {
                        int last_offset = -1;
                        int last_row = -1;
@@ -1177,8 +1235,13 @@ namespace Mono.CompilerServices.SymbolWriter
                                bw.Write (real_name);
                        }
 
+                       foreach (var lne in lnt.LineNumbers) {
+                               if (lne.EndRow != -1 || lne.EndColumn != -1)
+                                       flags |= Flags.EndInfoIncluded;
+                       }
+
                        LineNumberTableOffset = (int) bw.BaseStream.Position;
-                       lnt.Write (file, bw);
+                       lnt.Write (file, bw, (flags & Flags.ColumnsInfoIncluded) != 0, (flags & Flags.EndInfoIncluded) != 0);
 
                        DataOffset = (int) bw.BaseStream.Position;
 
@@ -1193,6 +1256,15 @@ namespace Mono.CompilerServices.SymbolWriter
                        bw.WriteLeb128 ((int) flags);
                }
 
+               public void ReadAll ()
+               {
+                       GetLineNumberTable ();
+                       GetLocals ();
+                       GetCodeBlocks ();
+                       GetScopeVariables ();
+                       GetRealName ();
+               }
+
                public LineNumberTable GetLineNumberTable ()
                {
                        lock (SymbolFile) {
@@ -1206,7 +1278,7 @@ namespace Mono.CompilerServices.SymbolWriter
                                long old_pos = reader.BaseStream.Position;
                                reader.BaseStream.Position = LineNumberTableOffset;
 
-                               lnt = LineNumberTable.Read (SymbolFile, reader);
+                               lnt = LineNumberTable.Read (SymbolFile, reader, (flags & Flags.ColumnsInfoIncluded) != 0, (flags & Flags.EndInfoIncluded) != 0);
 
                                reader.BaseStream.Position = old_pos;
                                return lnt;