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