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