2003-03-13 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 : 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                         SourceFile source_info = new SourceFile (file, url);
283                         sources.Add (url, source_info);
284                         return source_info;
285                 }
286
287                 public void DefineField (
288                         SymbolToken parent,
289                         string name,
290                         FieldAttributes attributes,
291                         byte[] signature,
292                         SymAddressKind addrKind,
293                         int addr1,
294                         int addr2,
295                         int addr3)
296                 {
297                         throw new NotSupportedException ();
298                 }
299
300                 public void DefineGlobalVariable (
301                         string name,
302                         FieldAttributes attributes,
303                         byte[] signature,
304                         SymAddressKind addrKind,
305                         int addr1,
306                         int addr2,
307                         int addr3)
308                 {
309                         throw new NotSupportedException ();
310                 }
311
312                 public void DefineLocalVariable (string name,
313                                                  FieldAttributes attributes,
314                                                  byte[] signature,
315                                                  SymAddressKind addrKind,
316                                                  int addr1,
317                                                  int addr2,
318                                                  int addr3,
319                                                  int startOffset,
320                                                  int endOffset)
321                 {
322                         if (current_method == null)
323                                 return;
324
325                         current_method.AddLocal (name, attributes, signature);
326                 }
327
328                 public void DefineParameter (string name,
329                                              ParameterAttributes attributes,
330                                              int sequence,
331                                              SymAddressKind addrKind,
332                                              int addr1,
333                                              int addr2,
334                                              int addr3)
335                 {
336                         throw new NotSupportedException ();
337                 }
338
339                 public void DefineSequencePoints (ISymbolDocumentWriter document,
340                                                   int[] offsets,
341                                                   int[] lines,
342                                                   int[] columns,
343                                                   int[] endLines,
344                                                   int[] endColumns)
345                 {
346                         throw new NotSupportedException ();
347                 }
348
349                 public void MarkSequencePoint (int offset, int line, int column)
350                 {
351                         if (current_method == null)
352                                 return;
353
354                         LineNumberEntry source_line = new LineNumberEntry (line, offset);
355                         current_method.AddLine (source_line);
356                 }
357
358                 public void Initialize (IntPtr emitter, string filename, bool fFullBuild)
359                 {
360                         throw new NotSupportedException ();
361                 }
362
363                 public void OpenMethod (SymbolToken symbol_token)
364                 {
365                         throw new NotSupportedException ();
366                 }
367
368                 public void SetMethodSourceRange (ISymbolDocumentWriter startDoc,
369                                                   int startLine, int startColumn,
370                                                   ISymbolDocumentWriter endDoc,
371                                                   int endLine, int endColumn)
372                 {
373                         throw new NotSupportedException ();
374                 }
375
376                 public void OpenMethod (ISymbolDocumentWriter document, int startLine, int startColumn,
377                                         int endLine, int endColumn, MethodBase method, int namespace_id)
378                 {
379                         SourceFile source_info = document as SourceFile;
380
381                         if ((source_info == null) || (method == null))
382                                 throw new NullReferenceException ();
383
384                         current_method = new SourceMethod (file, source_info, startLine, startColumn,
385                                                            endLine, endColumn, method, namespace_id);
386
387                         methods.Add (current_method);
388                         source_info.AddMethod (current_method);
389                 }
390
391                 public void CloseMethod ()
392                 {
393                         current_method = null;
394                 }
395
396                 public int DefineNamespace (string name, ISymbolDocumentWriter document,
397                                             string[] using_clauses, int parent)
398                 {
399                         if ((document == null) || (using_clauses == null))
400                                 throw new NullReferenceException ();
401                         if (!(document is SourceFile))
402                                 throw new ArgumentException ();
403
404                         SourceFile source_info = (SourceFile) document;
405
406                         return source_info.DefineNamespace (name, using_clauses, parent);
407                 }
408
409                 public void OpenNamespace (string name)
410                 {
411                         throw new NotSupportedException ();
412                 }
413
414                 public int OpenScope (int startOffset)
415                 {
416                         if (current_method == null)
417                                 return 0;
418
419                         current_method.StartBlock (startOffset);
420                         return 0;
421                 }
422
423                 public void CloseScope (int endOffset)
424                 {
425                         if (current_method == null)
426                                 return;
427
428                         current_method.EndBlock (endOffset);
429                 }
430
431                 public void SetScopeRange (int scopeID, int startOffset, int endOffset)
432                 {
433                         throw new NotSupportedException ();
434                 }
435
436                 public void SetSymAttribute (SymbolToken parent, string name, byte[] data)
437                 {
438                         throw new NotSupportedException ();
439                 }
440
441                 public void SetUnderlyingWriter (IntPtr underlyingWriter)
442                 {
443                         throw new NotSupportedException ();
444                 }
445
446                 public void SetUserEntryPoint (SymbolToken entryMethod)
447                 {
448                         throw new NotSupportedException ();
449                 }
450
451                 public void UsingNamespace (string fullName)
452                 {
453                         throw new NotSupportedException ();
454                 }
455
456                 //
457                 // MonoSymbolWriter implementation
458                 //
459                 protected void DoFixups (Assembly assembly)
460                 {
461                         foreach (SourceMethod method in methods) {
462                                 if (method._method_base is MethodBuilder) {
463                                         MethodBuilder mb = (MethodBuilder) method._method_base;
464                                         method._token = mb.GetToken ().Token;
465                                 } else if (method._method_base is ConstructorBuilder) {
466                                         ConstructorBuilder cb = (ConstructorBuilder) method._method_base;
467                                         method._token = cb.GetToken ().Token;
468                                 } else
469                                         throw new NotSupportedException ();
470
471                                 if (method.SourceFile == null)
472                                         orphant_methods.Add (method);
473                         }
474                 }
475
476                 protected byte[] CreateOutput (Assembly assembly)
477                 {
478                         foreach (SourceMethod method in Methods) {
479                                 if (!method.HasSource) {
480                                         Console.WriteLine ("INGORING METHOD: {0}", method);
481                                         continue;
482                                 }
483
484                                 method.SourceFile.DefineMethod (
485                                         method.MethodBase, method.Token, method.Locals,
486                                         method.Lines, method.Blocks, method.Start.Row, method.End.Row,
487                                         method.NamespaceID);
488                         }
489
490                         return file.CreateSymbolFile ();
491                 }
492         }
493 }
494