Close() must not be called.
[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                         throw new InvalidOperationException ();
373                 }
374
375                 public byte[] CreateSymbolFile (AssemblyBuilder assembly_builder)
376                 {
377                         DoFixups (assembly_builder);
378
379                         return CreateOutput (assembly_builder);
380                 }
381
382                 public void CloseNamespace () {
383                 }
384
385                 // Create and return a new IMonoSymbolDocumentWriter.
386                 public ISymbolDocumentWriter DefineDocument (string url,
387                                                              Guid language,
388                                                              Guid languageVendor,
389                                                              Guid documentType)
390                 {
391                         return new MonoSymbolDocumentWriter (url);
392                 }
393
394                 public void DefineField (
395                         SymbolToken parent,
396                         string name,
397                         FieldAttributes attributes,
398                         byte[] signature,
399                         SymAddressKind addrKind,
400                         int addr1,
401                         int addr2,
402                         int addr3)
403                 {
404                         throw new NotSupportedException ();
405                 }
406
407                 public void DefineGlobalVariable (
408                         string name,
409                         FieldAttributes attributes,
410                         byte[] signature,
411                         SymAddressKind addrKind,
412                         int addr1,
413                         int addr2,
414                         int addr3)
415                 {
416                         throw new NotSupportedException ();
417                 }
418
419                 public void DefineLocalVariable (string name,
420                                                  FieldAttributes attributes,
421                                                  byte[] signature,
422                                                  SymAddressKind addrKind,
423                                                  int addr1,
424                                                  int addr2,
425                                                  int addr3,
426                                                  int startOffset,
427                                                  int endOffset)
428                 {
429                         if (current_method == null)
430                                 return;
431
432                         current_method.AddLocal (new LocalVariableEntry (name, attributes, signature));
433                 }
434
435                 public void DefineParameter (string name,
436                                              ParameterAttributes attributes,
437                                              int sequence,
438                                              SymAddressKind addrKind,
439                                              int addr1,
440                                              int addr2,
441                                              int addr3)
442                 {
443                         throw new NotSupportedException ();
444                 }
445
446                 public void DefineSequencePoints (ISymbolDocumentWriter document,
447                                                   int[] offsets,
448                                                   int[] lines,
449                                                   int[] columns,
450                                                   int[] endLines,
451                                                   int[] endColumns)
452                 {
453                         if (current_method == null)
454                                 return;
455
456                         LineNumberEntry source_line = new LineNumberEntry (lines [0], offsets [0]);
457
458                         if (current_method != null)
459                                 current_method.AddLine (source_line);
460                 }
461
462                 public void Initialize (IntPtr emitter, string filename, bool fFullBuild)
463                 {
464                         throw new NotSupportedException ();
465                 }
466
467                 public void Initialize (string filename)
468                 {
469                         this.output_filename = filename;
470                 }
471
472                 public void OpenMethod (SymbolToken symbol_token)
473                 {
474                         int token = symbol_token.GetToken ();
475
476                         if ((token & 0xff000000) != 0x06000000)
477                                 throw new ArgumentException ();
478
479                         int index = (token & 0xffffff) - 1;
480
481                         MethodBase mb = (MethodBase) mbuilder_array [index];
482
483                         current_method = new SourceMethod (mb);
484
485                         methods.Add (current_method);
486                 }
487
488                 public void SetMethodSourceRange (ISymbolDocumentWriter startDoc,
489                                                   int startLine, int startColumn,
490                                                   ISymbolDocumentWriter endDoc,
491                                                   int endLine, int endColumn)
492                 {
493                         if (current_method == null)
494                                 return;
495
496                         if ((startDoc == null) || (endDoc == null))
497                                 throw new NullReferenceException ();
498
499                         if (!(startDoc is MonoSymbolDocumentWriter) || !(endDoc is MonoSymbolDocumentWriter))
500                                 throw new NotSupportedException ("both startDoc and endDoc must be of type "
501                                                                  + "MonoSymbolDocumentWriter");
502
503                         if (!startDoc.Equals (endDoc))
504                                 throw new NotSupportedException ("startDoc and endDoc must be the same");
505
506                         string source_file = ((MonoSymbolDocumentWriter) startDoc).FileName;
507                         SourceFile source_info;
508
509                         if (sources.ContainsKey (source_file))
510                                 source_info = (SourceFile) sources [source_file];
511                         else {
512                                 source_info = new SourceFile (source_file);
513                                 sources.Add (source_file, source_info);
514                         }
515
516                         current_method.SetSourceRange (source_info, startLine, startColumn,
517                                                        endLine, endColumn);
518
519                         source_info.AddMethod (current_method);
520                 }
521
522                 public void CloseMethod () {
523                         current_method = null;
524                 }
525
526                 public void OpenNamespace (string name)
527                 {
528                         throw new NotSupportedException ();
529                 }
530
531                 public int OpenScope (int startOffset)
532                 {
533                         if (current_method == null)
534                                 return 0;
535
536                         SourceBlock block = new SourceBlock (current_method, startOffset);
537                         current_method.StartBlock (block);
538
539                         return block.ID;
540                 }
541
542                 public void CloseScope (int endOffset) {
543                         if (current_method == null)
544                                 return;
545
546                         current_method.EndBlock (endOffset);
547                 }
548
549                 public void SetScopeRange (int scopeID, int startOffset, int endOffset)
550                 {
551                         if (current_method == null)
552                                 return;
553
554                         current_method.SetBlockRange (scopeID, startOffset, endOffset);
555                 }
556
557                 public void SetSymAttribute (SymbolToken parent, string name, byte[] data)
558                 {
559                         throw new NotSupportedException ();
560                 }
561
562                 public void SetUnderlyingWriter (IntPtr underlyingWriter)
563                 {
564                         throw new NotSupportedException ();
565                 }
566
567                 public void SetUserEntryPoint (SymbolToken entryMethod)
568                 {
569                         throw new NotSupportedException ();
570                 }
571
572                 public void UsingNamespace (string fullName)
573                 {
574                         throw new NotSupportedException ();
575                 }
576
577                 //
578                 // MonoSymbolWriter implementation
579                 //
580                 protected void DoFixups (Assembly assembly)
581                 {
582                         foreach (SourceMethod method in methods) {
583                                 if (method._method_base is MethodBuilder) {
584                                         MethodBuilder mb = (MethodBuilder) method._method_base;
585                                         method._token = mb.GetToken ().Token;
586                                 } else if (method._method_base is ConstructorBuilder) {
587                                         ConstructorBuilder cb = (ConstructorBuilder) method._method_base;
588                                         method._token = cb.GetToken ().Token;
589                                 } else
590                                         throw new NotSupportedException ();
591
592                                 if (method.SourceFile == null)
593                                         orphant_methods.Add (method);
594                         }
595                 }
596
597                 protected byte[] CreateOutput (Assembly assembly)
598                 {
599                         MonoSymbolFile file = new MonoSymbolFile ();
600
601                         foreach (SourceMethod method in Methods) {
602                                 if (!method.HasSource) {
603                                         Console.WriteLine ("INGORING METHOD: {0}", method);
604                                         continue;
605                                 }
606
607                                 SourceFileEntry source = file.DefineSource (method.SourceFile.FileName);
608
609                                 source.DefineMethod (method.MethodBase, method.Token, method.Locals,
610                                                      method.Lines, method.Start.Row, method.End.Row);
611                         }
612
613                         return file.CreateSymbolFile ();
614                 }
615         }
616 }
617