2003-02-07 Martin Baulig <martin@ximian.com>
[mono.git] / mcs / class / Mono.CSharp.Debugger / MonoSymbolWriter.cs
1 //
2 // System.Diagnostics.SymbolStore/MonoSymbolWriter.cs
3 //
4 // Author:
5 //   Martin Baulig (martin@gnome.org)
6 //
7 // This is the default implementation of the System.Diagnostics.SymbolStore.ISymbolWriter
8 // interface.
9 //
10 // (C) 2002 Ximian, Inc.  http://www.ximian.com
11 //
12
13 using System;
14 using System.Reflection;
15 using System.Reflection.Emit;
16 using System.Runtime.CompilerServices;
17 using System.Diagnostics.SymbolStore;
18 using System.Collections;
19 using System.IO;
20         
21 namespace Mono.CSharp.Debugger
22 {
23         internal class SourceFile
24         {
25                 private ArrayList _methods = new ArrayList ();
26                 private string _file_name;
27
28                 public SourceFile (string filename)
29                 {
30                         this._file_name = filename;
31                 }
32
33                 public override string ToString ()
34                 {
35                         return _file_name;
36                 }
37
38                 public string FileName {
39                         get {
40                                 return _file_name;
41                         }
42                 }
43
44                 public SourceMethod[] Methods {
45                         get {
46                                 SourceMethod[] retval = new SourceMethod [_methods.Count];
47                                 _methods.CopyTo (retval);
48                                 return retval;
49                         }
50                 }
51
52                 public void AddMethod (SourceMethod method)
53                 {
54                         _methods.Add (method);
55                 }
56         }
57
58         internal class SourceBlock
59         {
60                 static private int next_index;
61                 private readonly int _index;
62
63                 public SourceBlock (SourceMethod method, LineNumberEntry start, LineNumberEntry end)
64                 {
65                         this._method = method;
66                         this._start = start;
67                         this._end = end;
68                         this._index = ++next_index;
69                 }
70
71                 internal SourceBlock (SourceMethod method, int startOffset)
72                 {
73                         this._method = method;
74                         this._start_offset = startOffset;
75                         this._index = ++next_index;
76                 }
77
78                 public override string ToString ()
79                 {
80                         return "SourceBlock #" + ID + " (" + Start + " - " + End + ")";
81                 }
82
83                 private readonly SourceMethod _method;
84                 private ArrayList _blocks = new ArrayList ();
85                 internal LineNumberEntry _start = LineNumberEntry.Null;
86                 internal LineNumberEntry _end = LineNumberEntry.Null;
87                 internal int _start_offset, _end_offset;
88                 bool _has_source;
89
90                 internal void SetSourceRange (int startLine, int endLine)
91                 {
92                         _start = new LineNumberEntry (startLine, _start_offset);
93                         _end = new LineNumberEntry (endLine, _end_offset);
94                         _has_source = true;
95                 }
96
97                 private ArrayList _locals = new ArrayList ();
98
99                 public SourceMethod SourceMethod {
100                         get {
101                                 return _method;
102                         }
103                 }
104
105                 public SourceBlock[] Blocks {
106                         get {
107                                 SourceBlock[] retval = new SourceBlock [_blocks.Count];
108                                 _blocks.CopyTo (retval);
109                                 return retval;
110                         }
111                 }
112
113                 public void AddBlock (SourceBlock block)
114                 {
115                         _blocks.Add (block);
116                 }
117
118                 public bool HasSource {
119                         get {
120                                 return _has_source;
121                         }
122                 }
123
124                 public LineNumberEntry Start {
125                         get {
126                                 return _start;
127                         }
128                 }
129
130                 public LineNumberEntry End {
131                         get {
132                                 return _end;
133                         }
134                 }
135
136                 public int ID {
137                         get {
138                                 return _index;
139                         }
140                 }
141
142                 public LocalVariableEntry[] Locals {
143                         get {
144                                 LocalVariableEntry[] retval = new LocalVariableEntry [_locals.Count];
145                                 _locals.CopyTo (retval);
146                                 return retval;
147                         }
148                 }
149
150                 public void AddLocal (LocalVariableEntry local)
151                 {
152                         _locals.Add (local);
153                 }
154         }
155
156         internal class SourceMethod
157         {
158                 private ArrayList _lines = new ArrayList ();
159                 private ArrayList _blocks = new ArrayList ();
160                 private Hashtable _block_hash = new Hashtable ();
161                 private Stack _block_stack = new Stack ();
162
163                 internal readonly MethodBase _method_base;
164                 internal SourceFile _source_file;
165                 internal int _token;
166
167                 private SourceBlock _implicit_block;
168
169                 public SourceMethod (MethodBase method_base, SourceFile source_file)
170                         : this (method_base)
171                 {
172                         this._source_file = source_file;
173                 }
174
175                 internal SourceMethod (MethodBase method_base)
176                 {
177                         this._method_base = method_base;
178
179                         this._implicit_block = new SourceBlock (this, 0);
180                 }
181
182                 public void SetSourceRange (SourceFile sourceFile,
183                                             int startLine, int startColumn,
184                                             int endLine, int endColumn)
185                 {
186                         _source_file = sourceFile;
187                         _implicit_block.SetSourceRange (startLine, endLine);
188                 }
189
190                 public void StartBlock (SourceBlock block)
191                 {
192                         _block_stack.Push (block);
193                 }
194
195                 public void EndBlock (int endOffset) {
196                         SourceBlock block = (SourceBlock) _block_stack.Pop ();
197
198                         block._end_offset = endOffset;
199
200                         if (_block_stack.Count > 0) {
201                                 SourceBlock parent = (SourceBlock) _block_stack.Peek ();
202
203                                 parent.AddBlock (block);
204                         } else
205                                 _blocks.Add (block);
206
207                         _block_hash.Add (block.ID, block);
208                 }
209
210                 public void SetBlockRange (int BlockID, int startOffset, int endOffset)
211                 {
212                         SourceBlock block = (SourceBlock) _block_hash [BlockID];
213                         block._start_offset = startOffset;
214                         block._end_offset = endOffset;
215                 }
216
217                 public SourceBlock CurrentBlock {
218                         get {
219                                 if (_block_stack.Count > 0)
220                                         return (SourceBlock) _block_stack.Peek ();
221                                 else
222                                         return _implicit_block;
223                         }
224                 }
225
226                 public LineNumberEntry[] Lines {
227                         get {
228                                 LineNumberEntry[] retval = new LineNumberEntry [_lines.Count];
229                                 _lines.CopyTo (retval);
230                                 return retval;
231                         }
232                 }
233
234                 public void AddLine (LineNumberEntry line)
235                 {
236                         _lines.Add (line);
237                 }
238
239                 public SourceBlock[] Blocks {
240                         get {
241                                 SourceBlock[] retval = new SourceBlock [_blocks.Count];
242                                 _blocks.CopyTo (retval);
243                                 return retval;
244                         }
245                 }
246
247                 public LocalVariableEntry[] Locals {
248                         get {
249                                 return _implicit_block.Locals;
250                         }
251                 }
252
253                 public void AddLocal (LocalVariableEntry local)
254                 {
255                         _implicit_block.AddLocal (local);
256                 }
257
258                 public MethodBase MethodBase {
259                         get {
260                                 return _method_base;
261                         }
262                 }
263
264                 public string FullName {
265                         get {
266                                 return _method_base.DeclaringType.FullName + "." + _method_base.Name;
267                         }
268                 }
269
270                 public Type ReturnType {
271                         get {
272                                 if (_method_base is MethodInfo)
273                                         return ((MethodInfo)_method_base).ReturnType;
274                                 else if (_method_base is ConstructorInfo)
275                                         return _method_base.DeclaringType;
276                                 else
277                                         throw new NotSupportedException ();
278                         }
279                 }
280
281                 public ParameterInfo[] Parameters {
282                         get {
283                                 if (_method_base == null)
284                                         return new ParameterInfo [0];
285
286                                 ParameterInfo [] retval = _method_base.GetParameters ();
287                                 if (retval == null)
288                                         return new ParameterInfo [0];
289                                 else
290                                         return retval;
291                         }
292                 }
293
294                 public SourceFile SourceFile {
295                         get {
296                                 return _source_file;
297                         }
298                 }
299
300                 public int Token {
301                         get {
302                                 if (_token != 0)
303                                         return _token;
304                                 else
305                                         throw new NotSupportedException ();
306                         }
307                 }
308
309                 public bool HasSource {
310                         get {
311                                 return _implicit_block.HasSource && (_source_file != null);
312                         }
313                 }
314
315                 public LineNumberEntry Start {
316                         get {
317                                 return _implicit_block.Start;
318                         }
319                 }
320
321                 public LineNumberEntry End {
322                         get {
323                                 return _implicit_block.End;
324                         }
325                 }
326         }
327
328         public class MonoSymbolWriter : IMonoSymbolWriter
329         {
330                 protected ModuleBuilder module_builder;
331                 protected ArrayList locals = null;
332                 protected ArrayList orphant_methods = null;
333                 protected ArrayList methods = null;
334                 protected Hashtable sources = null;
335                 private ArrayList mbuilder_array = null;
336
337                 internal SourceMethod[] Methods {
338                         get {
339                                 SourceMethod[] retval = new SourceMethod [methods.Count];
340                                 methods.CopyTo (retval);
341                                 return retval;
342                         }
343                 }
344
345                 internal SourceFile[] Sources {
346                         get {
347                                 SourceFile[] retval = new SourceFile [sources.Count];
348                                 sources.Values.CopyTo (retval, 0);
349                                 return retval;
350                         }
351                 }
352
353                 private SourceMethod current_method = null;
354                 private string output_filename = null;
355
356                 //
357                 // Interface IMonoSymbolWriter
358                 //
359
360                 public MonoSymbolWriter (ModuleBuilder mb, ArrayList mbuilder_array)
361                 {
362                         this.module_builder = mb;
363                         this.methods = new ArrayList ();
364                         this.sources = new Hashtable ();
365                         this.orphant_methods = new ArrayList ();
366                         this.locals = new ArrayList ();
367                         this.mbuilder_array = mbuilder_array;
368                 }
369
370                 public void Close () { }
371
372                 public byte[] CreateSymbolFile (AssemblyBuilder assembly_builder)
373                 {
374                         DoFixups (assembly_builder);
375
376                         return CreateOutput (assembly_builder);
377                 }
378
379                 public void CloseNamespace () {
380                 }
381
382                 // Create and return a new IMonoSymbolDocumentWriter.
383                 public ISymbolDocumentWriter DefineDocument (string url,
384                                                              Guid language,
385                                                              Guid languageVendor,
386                                                              Guid documentType)
387                 {
388                         return new MonoSymbolDocumentWriter (url);
389                 }
390
391                 public void DefineField (
392                         SymbolToken parent,
393                         string name,
394                         FieldAttributes attributes,
395                         byte[] signature,
396                         SymAddressKind addrKind,
397                         int addr1,
398                         int addr2,
399                         int addr3)
400                 {
401                         throw new NotSupportedException ();
402                 }
403
404                 public void DefineGlobalVariable (
405                         string name,
406                         FieldAttributes attributes,
407                         byte[] signature,
408                         SymAddressKind addrKind,
409                         int addr1,
410                         int addr2,
411                         int addr3)
412                 {
413                         throw new NotSupportedException ();
414                 }
415
416                 public void DefineLocalVariable (string name,
417                                                  FieldAttributes attributes,
418                                                  byte[] signature,
419                                                  SymAddressKind addrKind,
420                                                  int addr1,
421                                                  int addr2,
422                                                  int addr3,
423                                                  int startOffset,
424                                                  int endOffset)
425                 {
426                         if (current_method == null)
427                                 return;
428
429                         current_method.AddLocal (new LocalVariableEntry (name, attributes, signature));
430                 }
431
432                 public void DefineParameter (string name,
433                                              ParameterAttributes attributes,
434                                              int sequence,
435                                              SymAddressKind addrKind,
436                                              int addr1,
437                                              int addr2,
438                                              int addr3)
439                 {
440                         throw new NotSupportedException ();
441                 }
442
443                 public void DefineSequencePoints (ISymbolDocumentWriter document,
444                                                   int[] offsets,
445                                                   int[] lines,
446                                                   int[] columns,
447                                                   int[] endLines,
448                                                   int[] endColumns)
449                 {
450                         if (current_method == null)
451                                 return;
452
453                         LineNumberEntry source_line = new LineNumberEntry (lines [0], offsets [0]);
454
455                         if (current_method != null)
456                                 current_method.AddLine (source_line);
457                 }
458
459                 public void Initialize (IntPtr emitter, string filename, bool fFullBuild)
460                 {
461                         throw new NotSupportedException ();
462                 }
463
464                 public void Initialize (string filename)
465                 {
466                         this.output_filename = filename;
467                 }
468
469                 public void OpenMethod (SymbolToken symbol_token)
470                 {
471                         int token = symbol_token.GetToken ();
472
473                         if ((token & 0xff000000) != 0x06000000)
474                                 throw new ArgumentException ();
475
476                         int index = (token & 0xffffff) - 1;
477
478                         MethodBase mb = (MethodBase) mbuilder_array [index];
479
480                         current_method = new SourceMethod (mb);
481
482                         methods.Add (current_method);
483                 }
484
485                 public void SetMethodSourceRange (ISymbolDocumentWriter startDoc,
486                                                   int startLine, int startColumn,
487                                                   ISymbolDocumentWriter endDoc,
488                                                   int endLine, int endColumn)
489                 {
490                         if (current_method == null)
491                                 return;
492
493                         if ((startDoc == null) || (endDoc == null))
494                                 throw new NullReferenceException ();
495
496                         if (!(startDoc is MonoSymbolDocumentWriter) || !(endDoc is MonoSymbolDocumentWriter))
497                                 throw new NotSupportedException ("both startDoc and endDoc must be of type "
498                                                                  + "MonoSymbolDocumentWriter");
499
500                         if (!startDoc.Equals (endDoc))
501                                 throw new NotSupportedException ("startDoc and endDoc must be the same");
502
503                         string source_file = ((MonoSymbolDocumentWriter) startDoc).FileName;
504                         SourceFile source_info;
505
506                         if (sources.ContainsKey (source_file))
507                                 source_info = (SourceFile) sources [source_file];
508                         else {
509                                 source_info = new SourceFile (source_file);
510                                 sources.Add (source_file, source_info);
511                         }
512
513                         current_method.SetSourceRange (source_info, startLine, startColumn,
514                                                        endLine, endColumn);
515
516                         source_info.AddMethod (current_method);
517                 }
518
519                 public void CloseMethod () {
520                         current_method = null;
521                 }
522
523                 public void OpenNamespace (string name)
524                 {
525                         throw new NotSupportedException ();
526                 }
527
528                 public int OpenScope (int startOffset)
529                 {
530                         if (current_method == null)
531                                 return 0;
532
533                         SourceBlock block = new SourceBlock (current_method, startOffset);
534                         current_method.StartBlock (block);
535
536                         return block.ID;
537                 }
538
539                 public void CloseScope (int endOffset) {
540                         if (current_method == null)
541                                 return;
542
543                         current_method.EndBlock (endOffset);
544                 }
545
546                 public void SetScopeRange (int scopeID, int startOffset, int endOffset)
547                 {
548                         if (current_method == null)
549                                 return;
550
551                         current_method.SetBlockRange (scopeID, startOffset, endOffset);
552                 }
553
554                 public void SetSymAttribute (SymbolToken parent, string name, byte[] data)
555                 {
556                         throw new NotSupportedException ();
557                 }
558
559                 public void SetUnderlyingWriter (IntPtr underlyingWriter)
560                 {
561                         throw new NotSupportedException ();
562                 }
563
564                 public void SetUserEntryPoint (SymbolToken entryMethod)
565                 {
566                         throw new NotSupportedException ();
567                 }
568
569                 public void UsingNamespace (string fullName)
570                 {
571                         throw new NotSupportedException ();
572                 }
573
574                 //
575                 // MonoSymbolWriter implementation
576                 //
577                 protected void DoFixups (Assembly assembly)
578                 {
579                         foreach (SourceMethod method in methods) {
580                                 if (method._method_base is MethodBuilder) {
581                                         MethodBuilder mb = (MethodBuilder) method._method_base;
582                                         method._token = mb.GetToken ().Token;
583                                 } else if (method._method_base is ConstructorBuilder) {
584                                         ConstructorBuilder cb = (ConstructorBuilder) method._method_base;
585                                         method._token = cb.GetToken ().Token;
586                                 } else
587                                         throw new NotSupportedException ();
588
589                                 if (method.SourceFile == null)
590                                         orphant_methods.Add (method);
591                         }
592                 }
593
594                 protected byte[] CreateOutput (Assembly assembly)
595                 {
596                         MonoSymbolTableWriter writer = new MonoSymbolTableWriter ();
597                         return writer.CreateSymbolTable (this);
598                 }
599         }
600 }
601