2004-05-23 Ben Maurer <bmaurer@users.sourceforge.net>
[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                 LineNumberEntry [] lines;
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                                 return lines;
129                         }
130                 }
131
132                 static LocalVariableEntry [] locals_buf = new LocalVariableEntry [20];
133                 int locals_pos = 0;
134                 
135                 public LocalVariableEntry[] Locals {
136                         get {
137                                 if (locals_pos == 0)
138                                         return new LocalVariableEntry [0];
139                                 else {
140                                         LocalVariableEntry[] retval = new LocalVariableEntry [locals_pos];
141                                         Array.Copy (locals_buf, retval, locals_pos);
142                                         return retval;
143                                 }
144                         }
145                 }
146
147                 public void AddLocal (string name, FieldAttributes attributes, byte[] signature)
148                 {
149                         if (locals_pos == locals_buf.Length) {
150                                 LocalVariableEntry [] t = new LocalVariableEntry [locals_buf.Length * 2 + 1];
151                                 Array.Copy (locals_buf, t, locals_pos);
152                                 locals_buf = t;
153                         }
154                         locals_buf [locals_pos ++] = new LocalVariableEntry (name, attributes, signature, CurrentBlock.Index);
155                 }
156
157                 public MethodBase MethodBase {
158                         get {
159                                 return _method_base;
160                         }
161                 }
162
163                 public string FullName {
164                         get {
165                                 return _method_base.DeclaringType.FullName + "." + _method_base.Name;
166                         }
167                 }
168
169                 public Type ReturnType {
170                         get {
171                                 if (_method_base is MethodInfo)
172                                         return ((MethodInfo)_method_base).ReturnType;
173                                 else if (_method_base is ConstructorInfo)
174                                         return _method_base.DeclaringType;
175                                 else
176                                         throw new NotSupportedException ();
177                         }
178                 }
179
180                 public ParameterInfo[] Parameters {
181                         get {
182                                 if (_method_base == null)
183                                         return new ParameterInfo [0];
184
185                                 ParameterInfo [] retval = _method_base.GetParameters ();
186                                 if (retval == null)
187                                         return new ParameterInfo [0];
188                                 else
189                                         return retval;
190                         }
191                 }
192
193                 public SourceFile SourceFile {
194                         get {
195                                 return _source_file;
196                         }
197                 }
198
199                 public int Token {
200                         get {
201                                 if (_token != 0)
202                                         return _token;
203                                 else
204                                         throw new NotSupportedException ();
205                         }
206                 }
207
208                 public bool HasSource {
209                         get {
210                                 return _source_file != null;
211                         }
212                 }
213
214                 public LineNumberEntry Start {
215                         get {
216                                 return _start;
217                         }
218                 }
219
220                 public LineNumberEntry End {
221                         get {
222                                 return _end;
223                         }
224                 }
225
226                 public int NamespaceID {
227                         get {
228                                 return _namespace_id;
229                         }
230                 }
231                 
232                 //
233                 // Passes on the lines from the MonoSymbolWriter. This method is
234                 // free to mutate the lns array, and it does.
235                 //
236                 internal void SetLineNumbers (LineNumberEntry [] lns, int count)
237                 {
238                         int pos = 0;
239                         
240                         int last_offset = -1;
241                         int last_row = -1;
242                         for (int i = 0; i < count; i++) {
243                                 LineNumberEntry line = lns [i];
244
245                                 if (line.Offset > last_offset) {
246                                         if (last_row >= 0)
247                                                 lns [pos++] = new LineNumberEntry (last_row, last_offset);
248                                                 
249                                         last_row = line.Row;
250                                         last_offset = line.Offset;
251                                 } else if (line.Row > last_row) {
252                                         last_row = line.Row;
253                                 }
254                         }
255                         
256                         lines = new LineNumberEntry [count + ((last_row >= 0) ? 1 : 0)];
257                         Array.Copy (lns, lines, pos);
258                         if (last_row >= 0)
259                                 lines [pos] = new LineNumberEntry (last_row, last_offset);
260                 }
261         }
262
263         public class MonoSymbolWriter : IMonoSymbolWriter
264         {
265                 protected ModuleBuilder module_builder;
266                 protected ArrayList locals = null;
267                 protected ArrayList orphant_methods = null;
268                 protected ArrayList methods = null;
269                 protected Hashtable sources = null;
270                 private MonoSymbolFile file = null;
271                 
272                 LineNumberEntry [] current_method_lines;
273                 int current_method_lines_pos = 0;
274
275                 internal SourceMethod[] Methods {
276                         get {
277                                 SourceMethod[] retval = new SourceMethod [methods.Count];
278                                 methods.CopyTo (retval);
279                                 return retval;
280                         }
281                 }
282
283                 internal SourceFile[] Sources {
284                         get {
285                                 SourceFile[] retval = new SourceFile [sources.Count];
286                                 sources.Values.CopyTo (retval, 0);
287                                 return retval;
288                         }
289                 }
290
291                 private SourceMethod current_method = null;
292
293                 //
294                 // Interface IMonoSymbolWriter
295                 //
296
297                 public MonoSymbolWriter (ModuleBuilder mb)
298                 {
299                         this.module_builder = mb;
300                         this.methods = new ArrayList ();
301                         this.sources = new Hashtable ();
302                         this.orphant_methods = new ArrayList ();
303                         this.locals = new ArrayList ();
304                         this.file = new MonoSymbolFile ();
305                         
306                         this.current_method_lines = new LineNumberEntry [50];
307                 }
308
309                 public void Close ()
310                 {
311                         throw new InvalidOperationException ();
312                 }
313
314                 public byte[] CreateSymbolFile (AssemblyBuilder assembly_builder)
315                 {
316                         DoFixups (assembly_builder);
317
318                         return CreateOutput (assembly_builder);
319                 }
320
321                 public void CloseNamespace () {
322                 }
323
324                 // Create and return a new IMonoSymbolDocumentWriter.
325                 public ISymbolDocumentWriter DefineDocument (string url,
326                                                              Guid language,
327                                                              Guid languageVendor,
328                                                              Guid documentType)
329                 {
330                         if (sources.ContainsKey (url))
331                                 return (ISymbolDocumentWriter)sources [url];
332                         SourceFile source_info = new SourceFile (file, url);
333                         sources.Add (url, source_info);
334                         return source_info;
335                 }
336
337                 public void DefineField (
338                         SymbolToken parent,
339                         string name,
340                         FieldAttributes attributes,
341                         byte[] signature,
342                         SymAddressKind addrKind,
343                         int addr1,
344                         int addr2,
345                         int addr3)
346                 {
347                         throw new NotSupportedException ();
348                 }
349
350                 public void DefineGlobalVariable (
351                         string name,
352                         FieldAttributes attributes,
353                         byte[] signature,
354                         SymAddressKind addrKind,
355                         int addr1,
356                         int addr2,
357                         int addr3)
358                 {
359                         throw new NotSupportedException ();
360                 }
361
362                 public void DefineLocalVariable (string name,
363                                                  FieldAttributes attributes,
364                                                  byte[] signature,
365                                                  SymAddressKind addrKind,
366                                                  int addr1,
367                                                  int addr2,
368                                                  int addr3,
369                                                  int startOffset,
370                                                  int endOffset)
371                 {
372                         if (current_method == null)
373                                 return;
374
375                         current_method.AddLocal (name, attributes, signature);
376                 }
377
378                 public void DefineParameter (string name,
379                                              ParameterAttributes attributes,
380                                              int sequence,
381                                              SymAddressKind addrKind,
382                                              int addr1,
383                                              int addr2,
384                                              int addr3)
385                 {
386                         throw new NotSupportedException ();
387                 }
388
389                 public void DefineSequencePoints (ISymbolDocumentWriter document,
390                                                   int[] offsets,
391                                                   int[] lines,
392                                                   int[] columns,
393                                                   int[] endLines,
394                                                   int[] endColumns)
395                 {
396                         throw new NotSupportedException ();
397                 }
398
399                 public void MarkSequencePoint (int offset, int line, int column)
400                 {
401                         if (current_method == null)
402                                 return;
403
404                         if (current_method_lines_pos == current_method_lines.Length) {
405                                 LineNumberEntry [] tmp = current_method_lines;
406                                 current_method_lines = new LineNumberEntry [current_method_lines.Length * 2];
407                                 Array.Copy (tmp, current_method_lines, current_method_lines_pos);
408                         }
409                         
410                         current_method_lines [current_method_lines_pos++] = new LineNumberEntry (line, offset);
411                 }
412
413                 public void Initialize (IntPtr emitter, string filename, bool fFullBuild)
414                 {
415                         throw new NotSupportedException ();
416                 }
417
418                 public void OpenMethod (SymbolToken symbol_token)
419                 {
420                         throw new NotSupportedException ();
421                 }
422
423                 public void SetMethodSourceRange (ISymbolDocumentWriter startDoc,
424                                                   int startLine, int startColumn,
425                                                   ISymbolDocumentWriter endDoc,
426                                                   int endLine, int endColumn)
427                 {
428                         throw new NotSupportedException ();
429                 }
430
431                 public void OpenMethod (ISymbolDocumentWriter document, int startLine, int startColumn,
432                                         int endLine, int endColumn, MethodBase method, int namespace_id)
433                 {
434                         SourceFile source_info = document as SourceFile;
435
436                         if ((source_info == null) || (method == null))
437                                 throw new NullReferenceException ();
438
439                         current_method = new SourceMethod (file, source_info, startLine, startColumn,
440                                                            endLine, endColumn, method, namespace_id);
441
442                         methods.Add (current_method);
443                         source_info.AddMethod (current_method);
444                 }
445
446                 public void CloseMethod ()
447                 {
448                         current_method.SetLineNumbers (current_method_lines, current_method_lines_pos);
449                         current_method_lines_pos = 0;
450                         
451                         current_method = null;
452                 }
453
454                 public int DefineNamespace (string name, ISymbolDocumentWriter document,
455                                             string[] using_clauses, int parent)
456                 {
457                         if ((document == null) || (using_clauses == null))
458                                 throw new NullReferenceException ();
459                         if (!(document is SourceFile))
460                                 throw new ArgumentException ();
461
462                         SourceFile source_info = (SourceFile) document;
463
464                         return source_info.DefineNamespace (name, using_clauses, parent);
465                 }
466
467                 public void OpenNamespace (string name)
468                 {
469                         throw new NotSupportedException ();
470                 }
471
472                 public int OpenScope (int startOffset)
473                 {
474                         if (current_method == null)
475                                 return 0;
476
477                         current_method.StartBlock (startOffset);
478                         return 0;
479                 }
480
481                 public void CloseScope (int endOffset)
482                 {
483                         if (current_method == null)
484                                 return;
485
486                         current_method.EndBlock (endOffset);
487                 }
488
489                 public void SetScopeRange (int scopeID, int startOffset, int endOffset)
490                 {
491                         throw new NotSupportedException ();
492                 }
493
494                 public void SetSymAttribute (SymbolToken parent, string name, byte[] data)
495                 {
496                         throw new NotSupportedException ();
497                 }
498
499                 public void SetUnderlyingWriter (IntPtr underlyingWriter)
500                 {
501                         throw new NotSupportedException ();
502                 }
503
504                 public void SetUserEntryPoint (SymbolToken entryMethod)
505                 {
506                         throw new NotSupportedException ();
507                 }
508
509                 public void UsingNamespace (string fullName)
510                 {
511                         throw new NotSupportedException ();
512                 }
513
514                 //
515                 // MonoSymbolWriter implementation
516                 //
517                 protected void DoFixups (Assembly assembly)
518                 {
519                         foreach (SourceMethod method in methods) {
520                                 if (method._method_base is MethodBuilder) {
521                                         MethodBuilder mb = (MethodBuilder) method._method_base;
522                                         method._token = mb.GetToken ().Token;
523                                 } else if (method._method_base is ConstructorBuilder) {
524                                         ConstructorBuilder cb = (ConstructorBuilder) method._method_base;
525                                         method._token = cb.GetToken ().Token;
526                                 } else
527                                         throw new NotSupportedException ();
528
529                                 if (method.SourceFile == null)
530                                         orphant_methods.Add (method);
531                         }
532                 }
533
534                 protected byte[] CreateOutput (Assembly assembly)
535                 {
536                         foreach (SourceMethod method in Methods) {
537                                 if (!method.HasSource) {
538                                         Console.WriteLine ("INGORING METHOD: {0}", method);
539                                         continue;
540                                 }
541
542                                 method.SourceFile.DefineMethod (
543                                         method.MethodBase, method.Token, method.Locals,
544                                         method.Lines, method.Blocks, method.Start.Row, method.End.Row,
545                                         method.NamespaceID);
546                         }
547
548                         return file.CreateSymbolFile ();
549                 }
550         }
551 }
552