2003-12-08 Zoltan Varga <vargaz@freemail.hu>
[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 : SourceFileEntry, ISymbolDocumentWriter
24         {
25                 private ArrayList _methods = new ArrayList ();
26
27                 public SourceFile (MonoSymbolFile file, string filename)
28                         : base (file, filename)
29                 { }
30
31                 public new SourceMethod[] Methods {
32                         get {
33                                 SourceMethod[] retval = new SourceMethod [_methods.Count];
34                                 _methods.CopyTo (retval);
35                                 return retval;
36                         }
37                 }
38
39                 public void AddMethod (SourceMethod method)
40                 {
41                         _methods.Add (method);
42                 }
43
44                 void ISymbolDocumentWriter.SetCheckSum (Guid algorithmId, byte[] checkSum)
45                 {
46                         throw new NotSupportedException ();
47                 }
48
49                 void ISymbolDocumentWriter.SetSource (byte[] source)
50                 {
51                         throw new NotSupportedException ();
52                 }
53         }
54
55         internal class SourceMethod
56         {
57                 private ArrayList _lines = new ArrayList ();
58                 private ArrayList _locals;
59                 private ArrayList _blocks;
60                 private Stack _block_stack;
61                 private int next_block_id = 0;
62
63                 internal readonly MethodBase _method_base;
64                 internal SourceFile _source_file;
65                 internal int _token;
66                 private int _namespace_id;
67                 private LineNumberEntry _start, _end;
68                 private MonoSymbolFile _file;
69
70                 private LexicalBlockEntry _implicit_block;
71
72                 internal SourceMethod (MonoSymbolFile file, SourceFile source_file,
73                                        int startLine, int startColumn, int endLine, int endColumn,
74                                        MethodBase method_base, int namespace_id)
75                 {
76                         this._file = file;
77                         this._method_base = method_base;
78                         this._source_file = source_file;
79                         this._namespace_id = namespace_id;
80
81                         this._start = new LineNumberEntry (startLine, 0);
82                         this._end = new LineNumberEntry (endLine, 0);
83
84                         this._implicit_block = new LexicalBlockEntry (0, 0);
85                 }
86
87                 public void StartBlock (int startOffset)
88                 {
89                         LexicalBlockEntry block = new LexicalBlockEntry (++next_block_id, startOffset);
90                         if (_block_stack == null)
91                                 _block_stack = new Stack ();
92                         _block_stack.Push (block);
93                         if (_blocks == null)
94                                 _blocks = new ArrayList ();
95                         _blocks.Add (block);
96                 }
97
98                 public void EndBlock (int endOffset)
99                 {
100                         LexicalBlockEntry block = (LexicalBlockEntry) _block_stack.Pop ();
101
102                         block.Close (endOffset);
103                 }
104
105                 public LexicalBlockEntry[] Blocks {
106                         get {
107                                 if (_blocks == null)
108                                         return new LexicalBlockEntry [0];
109                                 else {
110                                         LexicalBlockEntry[] retval = new LexicalBlockEntry [_blocks.Count];
111                                         _blocks.CopyTo (retval, 0);
112                                         return retval;
113                                 }
114                         }
115                 }
116
117                 public LexicalBlockEntry CurrentBlock {
118                         get {
119                                 if ((_block_stack != null) && (_block_stack.Count > 0))
120                                         return (LexicalBlockEntry) _block_stack.Peek ();
121                                 else
122                                         return _implicit_block;
123                         }
124                 }
125
126                 public LineNumberEntry[] Lines {
127                         get {
128                                 LineNumberEntry[] retval = new LineNumberEntry [_lines.Count];
129                                 _lines.CopyTo (retval);
130                                 return retval;
131                         }
132                 }
133
134                 public void AddLine (LineNumberEntry line)
135                 {
136                         _lines.Add (line);
137                 }
138
139                 public LocalVariableEntry[] Locals {
140                         get {
141                                 if (_locals == null)
142                                         return new LocalVariableEntry [0];
143                                 else {
144                                         LocalVariableEntry[] retval = new LocalVariableEntry [_locals.Count];
145                                         _locals.CopyTo (retval, 0);
146                                         return retval;
147                                 }
148                         }
149                 }
150
151                 public void AddLocal (string name, FieldAttributes attributes, byte[] signature)
152                 {
153                         if (_locals == null)
154                                 _locals = new ArrayList ();
155                         _locals.Add (new LocalVariableEntry (name, attributes, signature, CurrentBlock.Index));
156                 }
157
158                 public MethodBase MethodBase {
159                         get {
160                                 return _method_base;
161                         }
162                 }
163
164                 public string FullName {
165                         get {
166                                 return _method_base.DeclaringType.FullName + "." + _method_base.Name;
167                         }
168                 }
169
170                 public Type ReturnType {
171                         get {
172                                 if (_method_base is MethodInfo)
173                                         return ((MethodInfo)_method_base).ReturnType;
174                                 else if (_method_base is ConstructorInfo)
175                                         return _method_base.DeclaringType;
176                                 else
177                                         throw new NotSupportedException ();
178                         }
179                 }
180
181                 public ParameterInfo[] Parameters {
182                         get {
183                                 if (_method_base == null)
184                                         return new ParameterInfo [0];
185
186                                 ParameterInfo [] retval = _method_base.GetParameters ();
187                                 if (retval == null)
188                                         return new ParameterInfo [0];
189                                 else
190                                         return retval;
191                         }
192                 }
193
194                 public SourceFile SourceFile {
195                         get {
196                                 return _source_file;
197                         }
198                 }
199
200                 public int Token {
201                         get {
202                                 if (_token != 0)
203                                         return _token;
204                                 else
205                                         throw new NotSupportedException ();
206                         }
207                 }
208
209                 public bool HasSource {
210                         get {
211                                 return _source_file != null;
212                         }
213                 }
214
215                 public LineNumberEntry Start {
216                         get {
217                                 return _start;
218                         }
219                 }
220
221                 public LineNumberEntry End {
222                         get {
223                                 return _end;
224                         }
225                 }
226
227                 public int NamespaceID {
228                         get {
229                                 return _namespace_id;
230                         }
231                 }
232         }
233
234         public class MonoSymbolWriter : IMonoSymbolWriter
235         {
236                 protected ModuleBuilder module_builder;
237                 protected ArrayList locals = null;
238                 protected ArrayList orphant_methods = null;
239                 protected ArrayList methods = null;
240                 protected Hashtable sources = null;
241                 private MonoSymbolFile file = null;
242
243                 internal SourceMethod[] Methods {
244                         get {
245                                 SourceMethod[] retval = new SourceMethod [methods.Count];
246                                 methods.CopyTo (retval);
247                                 return retval;
248                         }
249                 }
250
251                 internal SourceFile[] Sources {
252                         get {
253                                 SourceFile[] retval = new SourceFile [sources.Count];
254                                 sources.Values.CopyTo (retval, 0);
255                                 return retval;
256                         }
257                 }
258
259                 private SourceMethod current_method = null;
260
261                 //
262                 // Interface IMonoSymbolWriter
263                 //
264
265                 public MonoSymbolWriter (ModuleBuilder mb)
266                 {
267                         this.module_builder = mb;
268                         this.methods = new ArrayList ();
269                         this.sources = new Hashtable ();
270                         this.orphant_methods = new ArrayList ();
271                         this.locals = new ArrayList ();
272                         this.file = new MonoSymbolFile ();
273                 }
274
275                 public void Close ()
276                 {
277                         throw new InvalidOperationException ();
278                 }
279
280                 public byte[] CreateSymbolFile (AssemblyBuilder assembly_builder)
281                 {
282                         DoFixups (assembly_builder);
283
284                         return CreateOutput (assembly_builder);
285                 }
286
287                 public void CloseNamespace () {
288                 }
289
290                 // Create and return a new IMonoSymbolDocumentWriter.
291                 public ISymbolDocumentWriter DefineDocument (string url,
292                                                              Guid language,
293                                                              Guid languageVendor,
294                                                              Guid documentType)
295                 {
296                         if (sources.ContainsKey (url))
297                                 return (ISymbolDocumentWriter)sources [url];
298                         SourceFile source_info = new SourceFile (file, url);
299                         sources.Add (url, source_info);
300                         return source_info;
301                 }
302
303                 public void DefineField (
304                         SymbolToken parent,
305                         string name,
306                         FieldAttributes attributes,
307                         byte[] signature,
308                         SymAddressKind addrKind,
309                         int addr1,
310                         int addr2,
311                         int addr3)
312                 {
313                         throw new NotSupportedException ();
314                 }
315
316                 public void DefineGlobalVariable (
317                         string name,
318                         FieldAttributes attributes,
319                         byte[] signature,
320                         SymAddressKind addrKind,
321                         int addr1,
322                         int addr2,
323                         int addr3)
324                 {
325                         throw new NotSupportedException ();
326                 }
327
328                 public void DefineLocalVariable (string name,
329                                                  FieldAttributes attributes,
330                                                  byte[] signature,
331                                                  SymAddressKind addrKind,
332                                                  int addr1,
333                                                  int addr2,
334                                                  int addr3,
335                                                  int startOffset,
336                                                  int endOffset)
337                 {
338                         if (current_method == null)
339                                 return;
340
341                         current_method.AddLocal (name, attributes, signature);
342                 }
343
344                 public void DefineParameter (string name,
345                                              ParameterAttributes attributes,
346                                              int sequence,
347                                              SymAddressKind addrKind,
348                                              int addr1,
349                                              int addr2,
350                                              int addr3)
351                 {
352                         throw new NotSupportedException ();
353                 }
354
355                 public void DefineSequencePoints (ISymbolDocumentWriter document,
356                                                   int[] offsets,
357                                                   int[] lines,
358                                                   int[] columns,
359                                                   int[] endLines,
360                                                   int[] endColumns)
361                 {
362                         throw new NotSupportedException ();
363                 }
364
365                 public void MarkSequencePoint (int offset, int line, int column)
366                 {
367                         if (current_method == null)
368                                 return;
369
370                         LineNumberEntry source_line = new LineNumberEntry (line, offset);
371                         current_method.AddLine (source_line);
372                 }
373
374                 public void Initialize (IntPtr emitter, string filename, bool fFullBuild)
375                 {
376                         throw new NotSupportedException ();
377                 }
378
379                 public void OpenMethod (SymbolToken symbol_token)
380                 {
381                         throw new NotSupportedException ();
382                 }
383
384                 public void SetMethodSourceRange (ISymbolDocumentWriter startDoc,
385                                                   int startLine, int startColumn,
386                                                   ISymbolDocumentWriter endDoc,
387                                                   int endLine, int endColumn)
388                 {
389                         throw new NotSupportedException ();
390                 }
391
392                 public void OpenMethod (ISymbolDocumentWriter document, int startLine, int startColumn,
393                                         int endLine, int endColumn, MethodBase method, int namespace_id)
394                 {
395                         SourceFile source_info = document as SourceFile;
396
397                         if ((source_info == null) || (method == null))
398                                 throw new NullReferenceException ();
399
400                         current_method = new SourceMethod (file, source_info, startLine, startColumn,
401                                                            endLine, endColumn, method, namespace_id);
402
403                         methods.Add (current_method);
404                         source_info.AddMethod (current_method);
405                 }
406
407                 public void CloseMethod ()
408                 {
409                         current_method = null;
410                 }
411
412                 public int DefineNamespace (string name, ISymbolDocumentWriter document,
413                                             string[] using_clauses, int parent)
414                 {
415                         if ((document == null) || (using_clauses == null))
416                                 throw new NullReferenceException ();
417                         if (!(document is SourceFile))
418                                 throw new ArgumentException ();
419
420                         SourceFile source_info = (SourceFile) document;
421
422                         return source_info.DefineNamespace (name, using_clauses, parent);
423                 }
424
425                 public void OpenNamespace (string name)
426                 {
427                         throw new NotSupportedException ();
428                 }
429
430                 public int OpenScope (int startOffset)
431                 {
432                         if (current_method == null)
433                                 return 0;
434
435                         current_method.StartBlock (startOffset);
436                         return 0;
437                 }
438
439                 public void CloseScope (int endOffset)
440                 {
441                         if (current_method == null)
442                                 return;
443
444                         current_method.EndBlock (endOffset);
445                 }
446
447                 public void SetScopeRange (int scopeID, int startOffset, int endOffset)
448                 {
449                         throw new NotSupportedException ();
450                 }
451
452                 public void SetSymAttribute (SymbolToken parent, string name, byte[] data)
453                 {
454                         throw new NotSupportedException ();
455                 }
456
457                 public void SetUnderlyingWriter (IntPtr underlyingWriter)
458                 {
459                         throw new NotSupportedException ();
460                 }
461
462                 public void SetUserEntryPoint (SymbolToken entryMethod)
463                 {
464                         throw new NotSupportedException ();
465                 }
466
467                 public void UsingNamespace (string fullName)
468                 {
469                         throw new NotSupportedException ();
470                 }
471
472                 //
473                 // MonoSymbolWriter implementation
474                 //
475                 protected void DoFixups (Assembly assembly)
476                 {
477                         foreach (SourceMethod method in methods) {
478                                 if (method._method_base is MethodBuilder) {
479                                         MethodBuilder mb = (MethodBuilder) method._method_base;
480                                         method._token = mb.GetToken ().Token;
481                                 } else if (method._method_base is ConstructorBuilder) {
482                                         ConstructorBuilder cb = (ConstructorBuilder) method._method_base;
483                                         method._token = cb.GetToken ().Token;
484                                 } else
485                                         throw new NotSupportedException ();
486
487                                 if (method.SourceFile == null)
488                                         orphant_methods.Add (method);
489                         }
490                 }
491
492                 protected byte[] CreateOutput (Assembly assembly)
493                 {
494                         foreach (SourceMethod method in Methods) {
495                                 if (!method.HasSource) {
496                                         Console.WriteLine ("INGORING METHOD: {0}", method);
497                                         continue;
498                                 }
499
500                                 method.SourceFile.DefineMethod (
501                                         method.MethodBase, method.Token, method.Locals,
502                                         method.Lines, method.Blocks, method.Start.Row, method.End.Row,
503                                         method.NamespaceID);
504                         }
505
506                         return file.CreateSymbolFile ();
507                 }
508         }
509 }
510