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