New test.
[mono.git] / mcs / class / Mono.CompilerServices.SymbolWriter / MonoSymbolTable.cs
1 //
2 // Mono.CSharp.Debugger/MonoSymbolTable.cs
3 //
4 // Author:
5 //   Martin Baulig (martin@ximian.com)
6 //
7 // (C) 2002 Ximian, Inc.  http://www.ximian.com
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 using System;
32 using System.Collections;
33 using System.Text;
34 using System.IO;
35
36 //
37 // Parts which are actually written into the symbol file are marked with
38 //
39 //         #region This is actually written to the symbol file
40 //         #endregion
41 //
42 // Please do not modify these regions without previously talking to me.
43 //
44 // All changes to the file format must be synchronized in several places:
45 //
46 // a) The fields in these regions (and their order) must match the actual
47 //    contents of the symbol file.
48 //
49 //    This helps people to understand the symbol file format without reading
50 //    too much source code, ie. you look at the appropriate region and then
51 //    you know what's actually in the file.
52 //
53 //    It is also required to help me enforce b).
54 //
55 // b) The regions must be kept in sync with the unmanaged code in
56 //    mono/metadata/debug-mono-symfile.h
57 //
58 // When making changes to the file format, you must also increase two version
59 // numbers:
60 //
61 // i)  OffsetTable.Version in this file.
62 // ii) MONO_SYMBOL_FILE_VERSION in mono/metadata/debug-mono-symfile.h
63 //
64 // After doing so, recompile everything, including the debugger.  Symbol files
65 // with different versions are incompatible to each other and the debugger and
66 // the runtime enfore this, so you need to recompile all your assemblies after
67 // changing the file format.
68 //
69
70 namespace Mono.CompilerServices.SymbolWriter
71 {
72         public struct OffsetTable
73         {
74                 public const int  Version = 39;
75                 public const long Magic   = 0x45e82623fd7fa614;
76
77                 #region This is actually written to the symbol file
78                 public int TotalFileSize;
79                 public int DataSectionOffset;
80                 public int DataSectionSize;
81                 public int SourceCount;
82                 public int SourceTableOffset;
83                 public int SourceTableSize;
84                 public int MethodCount;
85                 public int MethodTableOffset;
86                 public int MethodTableSize;
87                 public int TypeCount;
88                 #endregion
89
90                 internal OffsetTable (BinaryReader reader)
91                 {
92                         TotalFileSize = reader.ReadInt32 ();
93                         DataSectionOffset = reader.ReadInt32 ();
94                         DataSectionSize = reader.ReadInt32 ();
95                         SourceCount = reader.ReadInt32 ();
96                         SourceTableOffset = reader.ReadInt32 ();
97                         SourceTableSize = reader.ReadInt32 ();
98                         MethodCount = reader.ReadInt32 ();
99                         MethodTableOffset = reader.ReadInt32 ();
100                         MethodTableSize = reader.ReadInt32 ();
101                         TypeCount = reader.ReadInt32 ();
102                 }
103
104                 internal void Write (BinaryWriter bw)
105                 {
106                         bw.Write (TotalFileSize);
107                         bw.Write (DataSectionOffset);
108                         bw.Write (DataSectionSize);
109                         bw.Write (SourceCount);
110                         bw.Write (SourceTableOffset);
111                         bw.Write (SourceTableSize);
112                         bw.Write (MethodCount);
113                         bw.Write (MethodTableOffset);
114                         bw.Write (MethodTableSize);
115                         bw.Write (TypeCount);
116                 }
117
118                 public override string ToString ()
119                 {
120                         return String.Format (
121                                 "OffsetTable [{0} - {1}:{2} - {3}:{4}:{5} - {6}:{7}:{8} - {9}]",
122                                 TotalFileSize, DataSectionOffset, DataSectionSize, SourceCount,
123                                 SourceTableOffset, SourceTableSize, MethodCount, MethodTableOffset,
124                                 MethodTableSize, TypeCount);
125                 }
126         }
127
128         public struct LineNumberEntry
129         {
130                 #region This is actually written to the symbol file
131                 public readonly int Row;
132                 public readonly int Offset;
133                 #endregion
134
135                 public LineNumberEntry (int row, int offset)
136                 {
137                         this.Row = row;
138                         this.Offset = offset;
139                 }
140
141                 public static LineNumberEntry Null = new LineNumberEntry (0, 0);
142
143                 internal LineNumberEntry (BinaryReader reader)
144                 {
145                         Row = reader.ReadInt32 ();
146                         Offset = reader.ReadInt32 ();
147                 }
148
149                 internal void Write (BinaryWriter bw)
150                 {
151                         bw.Write (Row);
152                         bw.Write (Offset);
153                 }
154
155                 private class OffsetComparerClass : IComparer
156                 {
157                         public int Compare (object a, object b)
158                         {
159                                 LineNumberEntry l1 = (LineNumberEntry) a;
160                                 LineNumberEntry l2 = (LineNumberEntry) b;
161
162                                 if (l1.Offset < l2.Offset)
163                                         return -1;
164                                 else if (l1.Offset > l2.Offset)
165                                         return 1;
166                                 else
167                                         return 0;
168                         }
169                 }
170
171                 private class RowComparerClass : IComparer
172                 {
173                         public int Compare (object a, object b)
174                         {
175                                 LineNumberEntry l1 = (LineNumberEntry) a;
176                                 LineNumberEntry l2 = (LineNumberEntry) b;
177
178                                 if (l1.Row < l2.Row)
179                                         return -1;
180                                 else if (l1.Row > l2.Row)
181                                         return 1;
182                                 else
183                                         return 0;
184                         }
185                 }
186
187                 public static readonly IComparer OffsetComparer = new OffsetComparerClass ();
188                 public static readonly IComparer RowComparer = new RowComparerClass ();
189
190                 public override string ToString ()
191                 {
192                         return String.Format ("[Line {0}:{1}]", Row, Offset);
193                 }
194         }
195
196         public class LexicalBlockEntry
197         {
198                 public int Index;
199                 #region This is actually written to the symbol file
200                 public int StartOffset;
201                 public int EndOffset;
202                 #endregion
203
204                 public LexicalBlockEntry (int index, int start_offset)
205                 {
206                         this.Index = index;
207                         this.StartOffset = start_offset;
208                 }
209
210                 internal LexicalBlockEntry (int index, MyBinaryReader reader)
211                 {
212                         this.Index = index;
213                         this.StartOffset = reader.ReadInt32 ();
214                         this.EndOffset = reader.ReadInt32 ();
215                 }
216
217                 public void Close (int end_offset)
218                 {
219                         this.EndOffset = end_offset;
220                 }
221
222                 internal void Write (MyBinaryWriter bw)
223                 {
224                         bw.Write (StartOffset);
225                         bw.Write (EndOffset);
226                 }
227
228                 public override string ToString ()
229                 {
230                         return String.Format ("[LexicalBlock {0}:{1}]", StartOffset, EndOffset);
231                 }
232         }
233
234         public struct LocalVariableEntry
235         {
236                 #region This is actually written to the symbol file
237                 public readonly int Index;
238                 public readonly string Name;
239                 public readonly byte[] Signature;
240                 public readonly int BlockIndex;
241                 #endregion
242
243                 public LocalVariableEntry (int Index, string Name, byte[] Signature, int BlockIndex)
244                 {
245                         this.Index = Index;
246                         this.Name = Name;
247                         this.Signature = Signature;
248                         this.BlockIndex = BlockIndex;
249                 }
250
251                 internal LocalVariableEntry (MyBinaryReader reader)
252                 {
253                         Index = reader.ReadLeb128 ();
254                         Name = reader.ReadString ();
255                         int sig_length = reader.ReadLeb128 ();
256                         Signature = reader.ReadBytes (sig_length);
257                         BlockIndex = reader.ReadLeb128 ();
258                 }
259
260                 internal void Write (MonoSymbolFile file, MyBinaryWriter bw)
261                 {
262                         bw.WriteLeb128 (Index);
263                         bw.Write (Name);
264                         bw.WriteLeb128 ((int) Signature.Length);
265                         bw.Write (Signature);
266                         bw.WriteLeb128 (BlockIndex);
267                 }
268
269                 public override string ToString ()
270                 {
271                         return String.Format ("[LocalVariable {0}]", Name);
272                 }
273         }
274
275         public class SourceFileEntry
276         {
277                 #region This is actually written to the symbol file
278                 public readonly int Index;
279                 int Count;
280                 int NamespaceCount;
281                 int NameOffset;
282                 int MethodOffset;
283                 int NamespaceTableOffset;
284                 #endregion
285
286                 MonoSymbolFile file;
287                 string file_name;
288                 ArrayList methods;
289                 ArrayList namespaces;
290                 bool creating;
291
292                 public static int Size {
293                         get { return 24; }
294                 }
295
296                 public SourceFileEntry (MonoSymbolFile file, string file_name)
297                 {
298                         this.file = file;
299                         this.file_name = file_name;
300                         this.Index = file.AddSource (this);
301
302                         creating = true;
303                         methods = new ArrayList ();
304                         namespaces = new ArrayList ();
305                 }
306
307                 public void DefineMethod (string name, int token, LocalVariableEntry[] locals,
308                                           LineNumberEntry[] lines, LexicalBlockEntry[] blocks,
309                                           int start, int end, int namespace_id)
310                 {
311                         if (!creating)
312                                 throw new InvalidOperationException ();
313
314                         MethodEntry entry = new MethodEntry (
315                                 file, this, name, (int) token, locals, lines, blocks,
316                                 start, end, namespace_id);
317
318                         methods.Add (entry);
319                         file.AddMethod (entry);
320                 }
321
322                 public int DefineNamespace (string name, string[] using_clauses, int parent)
323                 {
324                         if (!creating)
325                                 throw new InvalidOperationException ();
326
327                         int index = file.GetNextNamespaceIndex ();
328                         NamespaceEntry ns = new NamespaceEntry (name, index, using_clauses, parent);
329                         namespaces.Add (ns);
330                         return index;
331                 }
332
333                 internal void WriteData (MyBinaryWriter bw)
334                 {
335                         NameOffset = (int) bw.BaseStream.Position;
336                         bw.Write (file_name);
337
338                         ArrayList list = new ArrayList ();
339                         foreach (MethodEntry entry in methods)
340                                 list.Add (entry.Write (file, bw));
341                         list.Sort ();
342                         Count = list.Count;
343
344                         MethodOffset = (int) bw.BaseStream.Position;
345                         foreach (MethodSourceEntry method in list)
346                                 method.Write (bw);
347
348                         NamespaceCount = namespaces.Count;
349                         NamespaceTableOffset = (int) bw.BaseStream.Position;
350                         foreach (NamespaceEntry ns in namespaces)
351                                 ns.Write (file, bw);
352                 }
353
354                 internal void Write (BinaryWriter bw)
355                 {
356                         bw.Write (Index);
357                         bw.Write (Count);
358                         bw.Write (NamespaceCount);
359                         bw.Write (NameOffset);
360                         bw.Write (MethodOffset);
361                         bw.Write (NamespaceTableOffset);
362                 }
363
364                 internal SourceFileEntry (MonoSymbolFile file, BinaryReader reader)
365                 {
366                         this.file = file;
367
368                         Index = reader.ReadInt32 ();
369                         Count = reader.ReadInt32 ();
370                         NamespaceCount = reader.ReadInt32 ();
371                         NameOffset = reader.ReadInt32 ();
372                         MethodOffset = reader.ReadInt32 ();
373                         NamespaceTableOffset = reader.ReadInt32 ();
374
375                         file_name = file.ReadString (NameOffset);
376                 }
377
378                 public string FileName {
379                         get { return file_name; }
380                 }
381
382                 public MethodSourceEntry[] Methods {
383                         get {
384                                 if (creating)
385                                         throw new InvalidOperationException ();
386
387                                 BinaryReader reader = file.BinaryReader;
388                                 int old_pos = (int) reader.BaseStream.Position;
389
390                                 reader.BaseStream.Position = MethodOffset;
391                                 ArrayList list = new ArrayList ();
392                                 for (int i = 0; i < Count; i ++)
393                                         list.Add (new MethodSourceEntry (reader));
394                                 reader.BaseStream.Position = old_pos;
395
396                                 MethodSourceEntry[] retval = new MethodSourceEntry [Count];
397                                 list.CopyTo (retval, 0);
398                                 return retval;
399                         }
400                 }
401
402                 public NamespaceEntry[] Namespaces {
403                         get {
404                                 if (creating)
405                                         throw new InvalidOperationException ();
406
407                                 MyBinaryReader reader = file.BinaryReader;
408                                 int old_pos = (int) reader.BaseStream.Position;
409
410                                 reader.BaseStream.Position = NamespaceTableOffset;
411                                 ArrayList list = new ArrayList ();
412                                 for (int i = 0; i < NamespaceCount; i ++)
413                                         list.Add (new NamespaceEntry (file, reader));
414                                 reader.BaseStream.Position = old_pos;
415
416                                 NamespaceEntry[] retval = new NamespaceEntry [list.Count];
417                                 list.CopyTo (retval, 0);
418                                 return retval;
419                         }
420                 }
421
422                 public override string ToString ()
423                 {
424                         return String.Format ("SourceFileEntry ({0}:{1}:{2})",
425                                               Index, file_name, Count);
426                 }
427         }
428
429         public struct MethodSourceEntry : IComparable
430         {
431                 #region This is actually written to the symbol file
432                 public readonly int Index;
433                 public readonly int FileOffset;
434                 public readonly int StartRow;
435                 public readonly int EndRow;
436                 #endregion
437
438                 public MethodSourceEntry (int index, int file_offset, int start, int end)
439                 {
440                         this.Index = index;
441                         this.FileOffset = file_offset;
442                         this.StartRow = start;
443                         this.EndRow = end;
444                 }
445
446                 internal MethodSourceEntry (BinaryReader reader)
447                 {
448                         Index = reader.ReadInt32 ();
449                         FileOffset = reader.ReadInt32 ();
450                         StartRow = reader.ReadInt32 ();
451                         EndRow = reader.ReadInt32 ();
452                 }
453
454                 public static int Size {
455                         get { return 16; }
456                 }
457
458                 internal void Write (BinaryWriter bw)
459                 {
460                         bw.Write (Index);
461                         bw.Write (FileOffset);
462                         bw.Write (StartRow);
463                         bw.Write (EndRow);
464                 }
465
466                 public int CompareTo (object obj)
467                 {
468                         MethodSourceEntry method = (MethodSourceEntry) obj;
469
470                         if (method.StartRow < StartRow)
471                                 return -1;
472                         else if (method.StartRow > StartRow)
473                                 return 1;
474                         else
475                                 return 0;
476                 }
477
478                 public override string ToString ()
479                 {
480                         return String.Format ("MethodSourceEntry ({0}:{1}:{2}:{3})",
481                                               Index, FileOffset, StartRow, EndRow);
482                 }
483         }
484
485         public struct MethodIndexEntry
486         {
487                 #region This is actually written to the symbol file
488                 public readonly int FileOffset;
489                 public readonly int Token;
490                 #endregion
491
492                 public static int Size {
493                         get { return 8; }
494                 }
495
496                 public MethodIndexEntry (int offset, int token)
497                 {
498                         this.FileOffset = offset;
499                         this.Token = token;
500                 }
501
502                 internal MethodIndexEntry (BinaryReader reader)
503                 {
504                         FileOffset = reader.ReadInt32 ();
505                         Token = reader.ReadInt32 ();
506                 }
507
508                 internal void Write (BinaryWriter bw)
509                 {
510                         bw.Write (FileOffset);
511                         bw.Write (Token);
512                 }
513
514                 public override string ToString ()
515                 {
516                         return String.Format ("MethodIndexEntry ({0}:{1:x})",
517                                               FileOffset, Token);
518                 }
519         }
520
521         public class MethodEntry : IComparable
522         {
523                 #region This is actually written to the symbol file
524                 public readonly int SourceFileIndex;
525                 public readonly int Token;
526                 public readonly int StartRow;
527                 public readonly int EndRow;
528                 public readonly int NumLocals;
529                 public readonly int NumLineNumbers;
530                 public readonly int NamespaceID;
531                 public readonly bool LocalNamesAmbiguous;
532
533                 int NameOffset;
534                 int TypeIndexTableOffset;
535                 int LocalVariableTableOffset;
536                 int LineNumberTableOffset;
537                 int NumLexicalBlocks;
538                 int LexicalBlockTableOffset;
539                 #endregion
540
541                 int index;
542                 int file_offset;
543
544                 public readonly SourceFileEntry SourceFile;
545                 public readonly LineNumberEntry[] LineNumbers;
546                 public readonly int[] LocalTypeIndices;
547                 public readonly LocalVariableEntry[] Locals;
548                 public readonly LexicalBlockEntry[] LexicalBlocks;
549
550                 public readonly MonoSymbolFile SymbolFile;
551
552                 public int Index {
553                         get { return index; }
554                         set { index = value; }
555                 }
556
557                 public static int Size {
558                         get { return 52; }
559                 }
560
561                 internal MethodEntry (MonoSymbolFile file, MyBinaryReader reader, int index)
562                 {
563                         this.SymbolFile = file;
564                         this.index = index;
565                         SourceFileIndex = reader.ReadInt32 ();
566                         Token = reader.ReadInt32 ();
567                         StartRow = reader.ReadInt32 ();
568                         EndRow = reader.ReadInt32 ();
569                         NumLocals = reader.ReadInt32 ();
570                         NumLineNumbers = reader.ReadInt32 ();
571                         NameOffset = reader.ReadInt32 ();
572                         TypeIndexTableOffset = reader.ReadInt32 ();
573                         LocalVariableTableOffset = reader.ReadInt32 ();
574                         LineNumberTableOffset = reader.ReadInt32 ();
575                         NumLexicalBlocks = reader.ReadInt32 ();
576                         LexicalBlockTableOffset = reader.ReadInt32 ();
577                         NamespaceID = reader.ReadInt32 ();
578                         LocalNamesAmbiguous = reader.ReadInt32 () != 0;
579
580                         SourceFile = file.GetSourceFile (SourceFileIndex);
581
582                         if (LineNumberTableOffset != 0) {
583                                 long old_pos = reader.BaseStream.Position;
584                                 reader.BaseStream.Position = LineNumberTableOffset;
585
586                                 LineNumbers = new LineNumberEntry [NumLineNumbers];
587
588                                 for (int i = 0; i < NumLineNumbers; i++)
589                                         LineNumbers [i] = new LineNumberEntry (reader);
590
591                                 reader.BaseStream.Position = old_pos;
592                         }
593
594                         if (LocalVariableTableOffset != 0) {
595                                 long old_pos = reader.BaseStream.Position;
596                                 reader.BaseStream.Position = LocalVariableTableOffset;
597
598                                 Locals = new LocalVariableEntry [NumLocals];
599
600                                 for (int i = 0; i < NumLocals; i++)
601                                         Locals [i] = new LocalVariableEntry (reader);
602
603                                 reader.BaseStream.Position = old_pos;
604                         }
605
606                         if (TypeIndexTableOffset != 0) {
607                                 long old_pos = reader.BaseStream.Position;
608                                 reader.BaseStream.Position = TypeIndexTableOffset;
609
610                                 LocalTypeIndices = new int [NumLocals];
611
612                                 for (int i = 0; i < NumLocals; i++)
613                                         LocalTypeIndices [i] = reader.ReadInt32 ();
614
615                                 reader.BaseStream.Position = old_pos;
616                         }
617
618                         if (LexicalBlockTableOffset != 0) {
619                                 long old_pos = reader.BaseStream.Position;
620                                 reader.BaseStream.Position = LexicalBlockTableOffset;
621
622                                 LexicalBlocks = new LexicalBlockEntry [NumLexicalBlocks];
623                                 for (int i = 0; i < NumLexicalBlocks; i++)
624                                         LexicalBlocks [i] = new LexicalBlockEntry (i, reader);
625
626                                 reader.BaseStream.Position = old_pos;
627                         }
628                 }
629
630                 internal MethodEntry (MonoSymbolFile file, SourceFileEntry source,
631                                       string name, int token, LocalVariableEntry[] locals,
632                                       LineNumberEntry[] lines, LexicalBlockEntry[] blocks,
633                                       int start_row, int end_row, int namespace_id)
634                 {
635                         this.SymbolFile = file;
636
637                         index = -1;
638
639                         Token = token;
640                         SourceFileIndex = source.Index;
641                         SourceFile = source;
642                         StartRow = start_row;
643                         EndRow = end_row;
644                         NamespaceID = namespace_id;
645                         LexicalBlocks = blocks;
646                         NumLexicalBlocks = LexicalBlocks != null ? LexicalBlocks.Length : 0;
647
648                         LineNumbers = BuildLineNumberTable (lines);
649                         NumLineNumbers = LineNumbers.Length;
650
651                         file.NumLineNumbers += NumLineNumbers;
652
653                         NumLocals = locals != null ? locals.Length : 0;
654                         Locals = locals;
655
656                         if (NumLocals <= 32) {
657                                 // Most of the time, the O(n^2) factor is actually
658                                 // less than the cost of allocating the hash table,
659                                 // 32 is a rough number obtained through some testing.
660                                 
661                                 for (int i = 0; i < NumLocals; i ++) {
662                                         string nm = locals [i].Name;
663                                         
664                                         for (int j = i + 1; j < NumLocals; j ++) {
665                                                 if (locals [j].Name == nm) {
666                                                         LocalNamesAmbiguous = true;
667                                                         goto locals_check_done;
668                                                 }
669                                         }
670                                 }
671                         locals_check_done :
672                                 ;
673                         } else {
674                                 Hashtable local_names = new Hashtable ();
675                                 foreach (LocalVariableEntry local in locals) {
676                                         if (local_names.Contains (local.Name)) {
677                                                 LocalNamesAmbiguous = true;
678                                                 break;
679                                         }
680                                         local_names.Add (local.Name, local);
681                                 }
682                         }
683
684                         LocalTypeIndices = new int [NumLocals];
685                         for (int i = 0; i < NumLocals; i++)
686                                 LocalTypeIndices [i] = file.GetNextTypeIndex ();
687                 }
688                 
689                 static LineNumberEntry [] tmp_buff = new LineNumberEntry [20];
690
691                 // BuildLineNumberTable() eliminates duplicate line numbers and ensures
692                 // we aren't going "backwards" since this would counfuse the runtime's
693                 // debugging code (and the debugger).
694                 //
695                 // In the line number table, the "offset" field most be strictly
696                 // monotonic increasing; that is, the next entry must not have an offset
697                 // which is equal to or less than the current one.
698                 //
699                 // The most common case is that our input (ie. the line number table as
700                 // we get it from mcs) contains several entries with the same offset
701                 // (and different line numbers) - but it may also happen that the offset
702                 // is decreasing (this can be considered as an exception, such lines will
703                 // simply be discarded).
704                 LineNumberEntry[] BuildLineNumberTable (LineNumberEntry[] line_numbers)
705                 {
706                         int pos = 0;
707                         int last_offset = -1;
708                         int last_row = -1;
709
710                         if (line_numbers == null)
711                                 return new LineNumberEntry [0];
712                         
713                         if (tmp_buff.Length < (line_numbers.Length + 1))
714                                 tmp_buff = new LineNumberEntry [(line_numbers.Length + 1) * 2];
715
716                         for (int i = 0; i < line_numbers.Length; i++) {
717                                 LineNumberEntry line = line_numbers [i];
718
719                                 if (line.Offset > last_offset) {
720                                         if (last_row >= 0)
721                                                 tmp_buff [pos ++] = new LineNumberEntry (last_row, last_offset);
722                                         last_row = line.Row;
723                                         last_offset = line.Offset;
724                                 } else if (line.Row > last_row) {
725                                         last_row = line.Row;
726                                 }
727                         }
728
729                         if (last_row >= 0)
730                                 tmp_buff [pos ++] = new LineNumberEntry (last_row, last_offset);
731
732                         LineNumberEntry [] retval = new LineNumberEntry [pos];
733                         Array.Copy (tmp_buff, retval, pos);
734                         return retval;
735                 }
736
737                 internal MethodSourceEntry Write (MonoSymbolFile file, MyBinaryWriter bw)
738                 {
739                         if (index <= 0)
740                                 throw new InvalidOperationException ();
741
742                         NameOffset = (int) bw.BaseStream.Position;
743
744                         TypeIndexTableOffset = (int) bw.BaseStream.Position;
745
746                         for (int i = 0; i < NumLocals; i++)
747                                 bw.Write (LocalTypeIndices [i]);
748
749                         LocalVariableTableOffset = (int) bw.BaseStream.Position;
750                         for (int i = 0; i < NumLocals; i++)
751                                 Locals [i].Write (file, bw);
752                         file.LocalCount += NumLocals;
753
754                         LineNumberTableOffset = (int) bw.BaseStream.Position;
755                         for (int i = 0; i < NumLineNumbers; i++)
756                                 LineNumbers [i].Write (bw);
757                         file.LineNumberCount += NumLineNumbers;
758
759                         LexicalBlockTableOffset = (int) bw.BaseStream.Position;
760                         for (int i = 0; i < NumLexicalBlocks; i++)
761                                 LexicalBlocks [i].Write (bw);
762                         file_offset = (int) bw.BaseStream.Position;
763
764                         bw.Write (SourceFileIndex);
765                         bw.Write (Token);
766                         bw.Write (StartRow);
767                         bw.Write (EndRow);
768                         bw.Write (NumLocals);
769                         bw.Write (NumLineNumbers);
770                         bw.Write (NameOffset);
771                         bw.Write (TypeIndexTableOffset);
772                         bw.Write (LocalVariableTableOffset);
773                         bw.Write (LineNumberTableOffset);
774                         bw.Write (NumLexicalBlocks);
775                         bw.Write (LexicalBlockTableOffset);
776                         bw.Write (NamespaceID);
777                         bw.Write (LocalNamesAmbiguous ? 1 : 0);
778
779                         return new MethodSourceEntry (index, file_offset, StartRow, EndRow);
780                 }
781
782                 internal void WriteIndex (BinaryWriter bw)
783                 {
784                         new MethodIndexEntry (file_offset, Token).Write (bw);
785                 }
786
787                 public int CompareTo (object obj)
788                 {
789                         MethodEntry method = (MethodEntry) obj;
790
791                         if (method.Token < Token)
792                                 return 1;
793                         else if (method.Token > Token)
794                                 return -1;
795                         else
796                                 return 0;
797                 }
798
799                 public override string ToString ()
800                 {
801                         return String.Format ("[Method {0}:{1}:{2}:{3}:{4} - {6}:{7} - {5}]",
802                                               index, Token, SourceFileIndex, StartRow, EndRow,
803                                               SourceFile, NumLocals, NumLineNumbers);
804                 }
805         }
806
807         public struct NamespaceEntry
808         {
809                 #region This is actually written to the symbol file
810                 public readonly string Name;
811                 public readonly int Index;
812                 public readonly int Parent;
813                 public readonly string[] UsingClauses;
814                 #endregion
815
816                 public NamespaceEntry (string name, int index, string[] using_clauses, int parent)
817                 {
818                         this.Name = name;
819                         this.Index = index;
820                         this.Parent = parent;
821                         this.UsingClauses = using_clauses != null ? using_clauses : new string [0];
822                 }
823
824                 internal NamespaceEntry (MonoSymbolFile file, MyBinaryReader reader)
825                 {
826                         Name = reader.ReadString ();
827                         Index = reader.ReadLeb128 ();
828                         Parent = reader.ReadLeb128 ();
829
830                         int count = reader.ReadLeb128 ();
831                         UsingClauses = new string [count];
832                         for (int i = 0; i < count; i++)
833                                 UsingClauses [i] = reader.ReadString ();
834                 }
835
836                 internal void Write (MonoSymbolFile file, MyBinaryWriter bw)
837                 {
838                         bw.Write (Name);
839                         bw.WriteLeb128 (Index);
840                         bw.WriteLeb128 (Parent);
841                         bw.WriteLeb128 (UsingClauses.Length);
842                         foreach (string uc in UsingClauses)
843                                 bw.Write (uc);
844                 }
845
846                 public override string ToString ()
847                 {
848                         return String.Format ("[Namespace {0}:{1}:{2}]", Name, Index, Parent);
849                 }
850         }
851 }