Reverted my last commit.
[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
257         public class MonoSymbolWriter : IMonoSymbolWriter
258         {
259                 protected ModuleBuilder module_builder;
260                 protected ArrayList locals = null;
261                 protected ArrayList orphant_methods = null;
262                 protected ArrayList methods = null;
263                 protected Hashtable sources = null;
264                 private MonoSymbolFile file = null;
265                 
266                 LineNumberEntry [] current_method_lines;
267                 int current_method_lines_pos = 0;
268
269                 internal SourceMethod[] Methods {
270                         get {
271                                 SourceMethod[] retval = new SourceMethod [methods.Count];
272                                 methods.CopyTo (retval);
273                                 return retval;
274                         }
275                 }
276
277                 internal SourceFile[] Sources {
278                         get {
279                                 SourceFile[] retval = new SourceFile [sources.Count];
280                                 sources.Values.CopyTo (retval, 0);
281                                 return retval;
282                         }
283                 }
284
285                 private SourceMethod current_method = null;
286
287                 //
288                 // Interface IMonoSymbolWriter
289                 //
290
291                 public MonoSymbolWriter (ModuleBuilder mb)
292                 {
293                         this.module_builder = mb;
294                         this.methods = new ArrayList ();
295                         this.sources = new Hashtable ();
296                         this.orphant_methods = new ArrayList ();
297                         this.locals = new ArrayList ();
298                         this.file = new MonoSymbolFile ();
299                         
300                         this.current_method_lines = new LineNumberEntry [50];
301                 }
302
303                 public void Close ()
304                 {
305                         throw new InvalidOperationException ();
306                 }
307
308                 public byte[] CreateSymbolFile (AssemblyBuilder assembly_builder)
309                 {
310                         DoFixups (assembly_builder);
311
312                         return CreateOutput (assembly_builder);
313                 }
314
315                 public void CloseNamespace () {
316                 }
317
318                 // Create and return a new IMonoSymbolDocumentWriter.
319                 public ISymbolDocumentWriter DefineDocument (string url,
320                                                              Guid language,
321                                                              Guid languageVendor,
322                                                              Guid documentType)
323                 {
324                         if (sources.ContainsKey (url))
325                                 return (ISymbolDocumentWriter)sources [url];
326                         SourceFile source_info = new SourceFile (file, url);
327                         sources.Add (url, source_info);
328                         return source_info;
329                 }
330
331                 public void DefineField (
332                         SymbolToken parent,
333                         string name,
334                         FieldAttributes attributes,
335                         byte[] signature,
336                         SymAddressKind addrKind,
337                         int addr1,
338                         int addr2,
339                         int addr3)
340                 {
341                         throw new NotSupportedException ();
342                 }
343
344                 public void DefineGlobalVariable (
345                         string name,
346                         FieldAttributes attributes,
347                         byte[] signature,
348                         SymAddressKind addrKind,
349                         int addr1,
350                         int addr2,
351                         int addr3)
352                 {
353                         throw new NotSupportedException ();
354                 }
355
356                 public void DefineLocalVariable (string name,
357                                                  FieldAttributes attributes,
358                                                  byte[] signature,
359                                                  SymAddressKind addrKind,
360                                                  int addr1,
361                                                  int addr2,
362                                                  int addr3,
363                                                  int startOffset,
364                                                  int endOffset)
365                 {
366                         if (current_method == null)
367                                 return;
368
369                         current_method.AddLocal (name, attributes, signature);
370                 }
371
372                 public void DefineParameter (string name,
373                                              ParameterAttributes attributes,
374                                              int sequence,
375                                              SymAddressKind addrKind,
376                                              int addr1,
377                                              int addr2,
378                                              int addr3)
379                 {
380                         throw new NotSupportedException ();
381                 }
382
383                 public void DefineSequencePoints (ISymbolDocumentWriter document,
384                                                   int[] offsets,
385                                                   int[] lines,
386                                                   int[] columns,
387                                                   int[] endLines,
388                                                   int[] endColumns)
389                 {
390                         throw new NotSupportedException ();
391                 }
392
393                 public void MarkSequencePoint (int offset, int line, int column)
394                 {
395                         if (current_method == null)
396                                 return;
397
398                         if (current_method_lines_pos == current_method_lines.Length) {
399                                 LineNumberEntry [] tmp = current_method_lines;
400                                 current_method_lines = new LineNumberEntry [current_method_lines.Length * 2];
401                                 Array.Copy (tmp, current_method_lines, current_method_lines_pos);
402                         }
403                         
404                         current_method_lines [current_method_lines_pos++] = new LineNumberEntry (line, offset);
405                 }
406
407                 public void Initialize (IntPtr emitter, string filename, bool fFullBuild)
408                 {
409                         throw new NotSupportedException ();
410                 }
411
412                 public void OpenMethod (SymbolToken symbol_token)
413                 {
414                         throw new NotSupportedException ();
415                 }
416
417                 public void SetMethodSourceRange (ISymbolDocumentWriter startDoc,
418                                                   int startLine, int startColumn,
419                                                   ISymbolDocumentWriter endDoc,
420                                                   int endLine, int endColumn)
421                 {
422                         throw new NotSupportedException ();
423                 }
424
425                 public void OpenMethod (ISymbolDocumentWriter document, int startLine, int startColumn,
426                                         int endLine, int endColumn, MethodBase method, int namespace_id)
427                 {
428                         SourceFile source_info = document as SourceFile;
429
430                         if ((source_info == null) || (method == null))
431                                 throw new NullReferenceException ();
432
433                         current_method = new SourceMethod (file, source_info, startLine, startColumn,
434                                                            endLine, endColumn, method, namespace_id);
435
436                         methods.Add (current_method);
437                         source_info.AddMethod (current_method);
438                 }
439
440                 public void CloseMethod ()
441                 {
442                         current_method.SetLineNumbers (current_method_lines, current_method_lines_pos);
443                         current_method_lines_pos = 0;
444                         
445                         current_method = null;
446                 }
447
448                 public int DefineNamespace (string name, ISymbolDocumentWriter document,
449                                             string[] using_clauses, int parent)
450                 {
451                         if ((document == null) || (using_clauses == null))
452                                 throw new NullReferenceException ();
453                         if (!(document is SourceFile))
454                                 throw new ArgumentException ();
455
456                         SourceFile source_info = (SourceFile) document;
457
458                         return source_info.DefineNamespace (name, using_clauses, parent);
459                 }
460
461                 public void OpenNamespace (string name)
462                 {
463                         throw new NotSupportedException ();
464                 }
465
466                 public int OpenScope (int startOffset)
467                 {
468                         if (current_method == null)
469                                 return 0;
470
471                         current_method.StartBlock (startOffset);
472                         return 0;
473                 }
474
475                 public void CloseScope (int endOffset)
476                 {
477                         if (current_method == null)
478                                 return;
479
480                         current_method.EndBlock (endOffset);
481                 }
482
483                 public void SetScopeRange (int scopeID, int startOffset, int endOffset)
484                 {
485                         throw new NotSupportedException ();
486                 }
487
488                 public void SetSymAttribute (SymbolToken parent, string name, byte[] data)
489                 {
490                         throw new NotSupportedException ();
491                 }
492
493                 public void SetUnderlyingWriter (IntPtr underlyingWriter)
494                 {
495                         throw new NotSupportedException ();
496                 }
497
498                 public void SetUserEntryPoint (SymbolToken entryMethod)
499                 {
500                         throw new NotSupportedException ();
501                 }
502
503                 public void UsingNamespace (string fullName)
504                 {
505                         throw new NotSupportedException ();
506                 }
507
508                 //
509                 // MonoSymbolWriter implementation
510                 //
511                 protected void DoFixups (Assembly assembly)
512                 {
513                         foreach (SourceMethod method in methods) {
514                                 if (method._method_base is MethodBuilder) {
515                                         MethodBuilder mb = (MethodBuilder) method._method_base;
516                                         method._token = mb.GetToken ().Token;
517                                 } else if (method._method_base is ConstructorBuilder) {
518                                         ConstructorBuilder cb = (ConstructorBuilder) method._method_base;
519                                         method._token = cb.GetToken ().Token;
520                                 } else
521                                         throw new NotSupportedException ();
522
523                                 if (method.SourceFile == null)
524                                         orphant_methods.Add (method);
525                         }
526                 }
527
528                 protected byte[] CreateOutput (Assembly assembly)
529                 {
530                         foreach (SourceMethod method in Methods) {
531                                 if (!method.HasSource) {
532                                         Console.WriteLine ("INGORING METHOD: {0}", method);
533                                         continue;
534                                 }
535
536                                 method.SourceFile.DefineMethod (
537                                         method.MethodBase, method.Token, method.Locals,
538                                         method.Lines, method.Blocks, method.Start.Row, method.End.Row,
539                                         method.NamespaceID);
540                         }
541
542                         return file.CreateSymbolFile ();
543                 }
544         }
545 }
546