Use my correct email address in the copyright info.
[mono.git] / mcs / class / Mono.CSharp.Debugger / MonoSymbolWriter.cs
1 //
2 // Mono.CSharp.Debugger/MonoSymbolWriter.cs
3 //
4 // Author:
5 //   Martin Baulig (martin@ximian.com)
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 //
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 // 
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 // 
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33
34 using System;
35 using System.Reflection;
36 using System.Reflection.Emit;
37 using System.Runtime.CompilerServices;
38 using System.Diagnostics.SymbolStore;
39 using System.Collections;
40 using System.IO;
41         
42 namespace Mono.CSharp.Debugger
43 {
44         internal class SourceFile : SourceFileEntry, ISymbolDocumentWriter
45         {
46                 private ArrayList _methods = new ArrayList ();
47
48                 public SourceFile (MonoSymbolFile file, string filename)
49                         : base (file, filename)
50                 { }
51
52                 public new SourceMethod[] Methods {
53                         get {
54                                 SourceMethod[] retval = new SourceMethod [_methods.Count];
55                                 _methods.CopyTo (retval);
56                                 return retval;
57                         }
58                 }
59
60                 public void AddMethod (SourceMethod method)
61                 {
62                         _methods.Add (method);
63                 }
64
65                 void ISymbolDocumentWriter.SetCheckSum (Guid algorithmId, byte[] checkSum)
66                 {
67                         throw new NotSupportedException ();
68                 }
69
70                 void ISymbolDocumentWriter.SetSource (byte[] source)
71                 {
72                         throw new NotSupportedException ();
73                 }
74         }
75
76         internal class SourceMethod
77         {
78                 LineNumberEntry [] lines;
79                 private ArrayList _locals;
80                 private ArrayList _blocks;
81                 private Stack _block_stack;
82                 private int next_block_id = 0;
83
84                 internal readonly MethodBase _method_base;
85                 internal SourceFile _source_file;
86                 internal int _token;
87                 private int _namespace_id;
88                 private LineNumberEntry _start, _end;
89                 private MonoSymbolFile _file;
90
91                 private LexicalBlockEntry _implicit_block;
92
93                 internal SourceMethod (MonoSymbolFile file, SourceFile source_file,
94                                        int startLine, int startColumn, int endLine, int endColumn,
95                                        MethodBase method_base, int namespace_id)
96                 {
97                         this._file = file;
98                         this._method_base = method_base;
99                         this._source_file = source_file;
100                         this._namespace_id = namespace_id;
101
102                         this._start = new LineNumberEntry (startLine, 0);
103                         this._end = new LineNumberEntry (endLine, 0);
104
105                         this._implicit_block = new LexicalBlockEntry (0, 0);
106                 }
107
108                 public void StartBlock (int startOffset)
109                 {
110                         LexicalBlockEntry block = new LexicalBlockEntry (++next_block_id, startOffset);
111                         if (_block_stack == null)
112                                 _block_stack = new Stack ();
113                         _block_stack.Push (block);
114                         if (_blocks == null)
115                                 _blocks = new ArrayList ();
116                         _blocks.Add (block);
117                 }
118
119                 public void EndBlock (int endOffset)
120                 {
121                         LexicalBlockEntry block = (LexicalBlockEntry) _block_stack.Pop ();
122
123                         block.Close (endOffset);
124                 }
125
126                 public LexicalBlockEntry[] Blocks {
127                         get {
128                                 if (_blocks == null)
129                                         return new LexicalBlockEntry [0];
130                                 else {
131                                         LexicalBlockEntry[] retval = new LexicalBlockEntry [_blocks.Count];
132                                         _blocks.CopyTo (retval, 0);
133                                         return retval;
134                                 }
135                         }
136                 }
137
138                 public LexicalBlockEntry CurrentBlock {
139                         get {
140                                 if ((_block_stack != null) && (_block_stack.Count > 0))
141                                         return (LexicalBlockEntry) _block_stack.Peek ();
142                                 else
143                                         return _implicit_block;
144                         }
145                 }
146
147                 public LineNumberEntry[] Lines {
148                         get {
149                                 return lines;
150                         }
151                 }
152
153                 public LocalVariableEntry[] Locals {
154                         get {
155                                 if (_locals == null)
156                                         return new LocalVariableEntry [0];
157                                 else {
158                                         LocalVariableEntry[] retval = new LocalVariableEntry [_locals.Count];
159                                         _locals.CopyTo (retval, 0);
160                                         return retval;
161                                 }
162                         }
163                 }
164
165                 public void AddLocal (string name, FieldAttributes attributes, byte[] signature)
166                 {
167                         if (_locals == null)
168                                 _locals = new ArrayList ();
169                         _locals.Add (new LocalVariableEntry (name, attributes, signature, CurrentBlock.Index));
170                 }
171
172                 public MethodBase MethodBase {
173                         get {
174                                 return _method_base;
175                         }
176                 }
177
178                 public string FullName {
179                         get {
180                                 return _method_base.DeclaringType.FullName + "." + _method_base.Name;
181                         }
182                 }
183
184                 public Type ReturnType {
185                         get {
186                                 if (_method_base is MethodInfo)
187                                         return ((MethodInfo)_method_base).ReturnType;
188                                 else if (_method_base is ConstructorInfo)
189                                         return _method_base.DeclaringType;
190                                 else
191                                         throw new NotSupportedException ();
192                         }
193                 }
194
195                 public ParameterInfo[] Parameters {
196                         get {
197                                 if (_method_base == null)
198                                         return new ParameterInfo [0];
199
200                                 ParameterInfo [] retval = _method_base.GetParameters ();
201                                 if (retval == null)
202                                         return new ParameterInfo [0];
203                                 else
204                                         return retval;
205                         }
206                 }
207
208                 public SourceFile SourceFile {
209                         get {
210                                 return _source_file;
211                         }
212                 }
213
214                 public int Token {
215                         get {
216                                 if (_token != 0)
217                                         return _token;
218                                 else
219                                         throw new NotSupportedException ();
220                         }
221                 }
222
223                 public bool HasSource {
224                         get {
225                                 return _source_file != null;
226                         }
227                 }
228
229                 public LineNumberEntry Start {
230                         get {
231                                 return _start;
232                         }
233                 }
234
235                 public LineNumberEntry End {
236                         get {
237                                 return _end;
238                         }
239                 }
240
241                 public int NamespaceID {
242                         get {
243                                 return _namespace_id;
244                         }
245                 }
246                 
247                 //
248                 // Passes on the lines from the MonoSymbolWriter. This method is
249                 // free to mutate the lns array, and it does.
250                 //
251                 internal void SetLineNumbers (LineNumberEntry [] lns, int count)
252                 {
253                         int pos = 0;
254                         
255                         int last_offset = -1;
256                         int last_row = -1;
257                         for (int i = 0; i < count; i++) {
258                                 LineNumberEntry line = lns [i];
259
260                                 if (line.Offset > last_offset) {
261                                         if (last_row >= 0)
262                                                 lns [pos++] = new LineNumberEntry (last_row, last_offset);
263                                                 
264                                         last_row = line.Row;
265                                         last_offset = line.Offset;
266                                 } else if (line.Row > last_row) {
267                                         last_row = line.Row;
268                                 }
269                         }
270                         
271                         lines = new LineNumberEntry [count + ((last_row >= 0) ? 1 : 0)];
272                         Array.Copy (lns, lines, pos);
273                         if (last_row >= 0)
274                                 lines [pos] = new LineNumberEntry (last_row, last_offset);
275                 }
276         }
277
278         public class MonoSymbolWriter : IMonoSymbolWriter
279         {
280                 protected ModuleBuilder module_builder;
281                 protected ArrayList locals = null;
282                 protected ArrayList orphant_methods = null;
283                 protected ArrayList methods = null;
284                 protected Hashtable sources = null;
285                 private MonoSymbolFile file = null;
286                 
287                 LineNumberEntry [] current_method_lines;
288                 int current_method_lines_pos = 0;
289
290                 internal SourceMethod[] Methods {
291                         get {
292                                 SourceMethod[] retval = new SourceMethod [methods.Count];
293                                 methods.CopyTo (retval);
294                                 return retval;
295                         }
296                 }
297
298                 internal SourceFile[] Sources {
299                         get {
300                                 SourceFile[] retval = new SourceFile [sources.Count];
301                                 sources.Values.CopyTo (retval, 0);
302                                 return retval;
303                         }
304                 }
305
306                 private SourceMethod current_method = null;
307
308                 //
309                 // Interface IMonoSymbolWriter
310                 //
311
312                 public MonoSymbolWriter (ModuleBuilder mb)
313                 {
314                         this.module_builder = mb;
315                         this.methods = new ArrayList ();
316                         this.sources = new Hashtable ();
317                         this.orphant_methods = new ArrayList ();
318                         this.locals = new ArrayList ();
319                         this.file = new MonoSymbolFile ();
320                         
321                         this.current_method_lines = new LineNumberEntry [50];
322                 }
323
324                 public void Close ()
325                 {
326                         throw new InvalidOperationException ();
327                 }
328
329                 public byte[] CreateSymbolFile (AssemblyBuilder assembly_builder)
330                 {
331                         DoFixups (assembly_builder);
332
333                         return CreateOutput (assembly_builder);
334                 }
335
336                 public void CloseNamespace () {
337                 }
338
339                 // Create and return a new IMonoSymbolDocumentWriter.
340                 public ISymbolDocumentWriter DefineDocument (string url,
341                                                              Guid language,
342                                                              Guid languageVendor,
343                                                              Guid documentType)
344                 {
345                         if (sources.ContainsKey (url))
346                                 return (ISymbolDocumentWriter)sources [url];
347                         SourceFile source_info = new SourceFile (file, url);
348                         sources.Add (url, source_info);
349                         return source_info;
350                 }
351
352                 public void DefineField (
353                         SymbolToken parent,
354                         string name,
355                         FieldAttributes attributes,
356                         byte[] signature,
357                         SymAddressKind addrKind,
358                         int addr1,
359                         int addr2,
360                         int addr3)
361                 {
362                         throw new NotSupportedException ();
363                 }
364
365                 public void DefineGlobalVariable (
366                         string name,
367                         FieldAttributes attributes,
368                         byte[] signature,
369                         SymAddressKind addrKind,
370                         int addr1,
371                         int addr2,
372                         int addr3)
373                 {
374                         throw new NotSupportedException ();
375                 }
376
377                 public void DefineLocalVariable (string name,
378                                                  FieldAttributes attributes,
379                                                  byte[] signature,
380                                                  SymAddressKind addrKind,
381                                                  int addr1,
382                                                  int addr2,
383                                                  int addr3,
384                                                  int startOffset,
385                                                  int endOffset)
386                 {
387                         if (current_method == null)
388                                 return;
389
390                         current_method.AddLocal (name, attributes, signature);
391                 }
392
393                 public void DefineParameter (string name,
394                                              ParameterAttributes attributes,
395                                              int sequence,
396                                              SymAddressKind addrKind,
397                                              int addr1,
398                                              int addr2,
399                                              int addr3)
400                 {
401                         throw new NotSupportedException ();
402                 }
403
404                 public void DefineSequencePoints (ISymbolDocumentWriter document,
405                                                   int[] offsets,
406                                                   int[] lines,
407                                                   int[] columns,
408                                                   int[] endLines,
409                                                   int[] endColumns)
410                 {
411                         throw new NotSupportedException ();
412                 }
413
414                 public void MarkSequencePoint (int offset, int line, int column)
415                 {
416                         if (current_method == null)
417                                 return;
418
419                         if (current_method_lines_pos == current_method_lines.Length) {
420                                 LineNumberEntry [] tmp = current_method_lines;
421                                 current_method_lines = new LineNumberEntry [current_method_lines.Length * 2];
422                                 Array.Copy (tmp, current_method_lines, current_method_lines_pos);
423                         }
424                         
425                         current_method_lines [current_method_lines_pos++] = new LineNumberEntry (line, offset);
426                 }
427
428                 public void Initialize (IntPtr emitter, string filename, bool fFullBuild)
429                 {
430                         throw new NotSupportedException ();
431                 }
432
433                 public void OpenMethod (SymbolToken symbol_token)
434                 {
435                         throw new NotSupportedException ();
436                 }
437
438                 public void SetMethodSourceRange (ISymbolDocumentWriter startDoc,
439                                                   int startLine, int startColumn,
440                                                   ISymbolDocumentWriter endDoc,
441                                                   int endLine, int endColumn)
442                 {
443                         throw new NotSupportedException ();
444                 }
445
446                 public void OpenMethod (ISymbolDocumentWriter document, int startLine, int startColumn,
447                                         int endLine, int endColumn, MethodBase method, int namespace_id)
448                 {
449                         SourceFile source_info = document as SourceFile;
450
451                         if ((source_info == null) || (method == null))
452                                 throw new NullReferenceException ();
453
454                         current_method = new SourceMethod (file, source_info, startLine, startColumn,
455                                                            endLine, endColumn, method, namespace_id);
456
457                         methods.Add (current_method);
458                         source_info.AddMethod (current_method);
459                 }
460
461                 public void CloseMethod ()
462                 {
463                         current_method.SetLineNumbers (current_method_lines, current_method_lines_pos);
464                         current_method_lines_pos = 0;
465                         
466                         current_method = null;
467                 }
468
469                 public int DefineNamespace (string name, ISymbolDocumentWriter document,
470                                             string[] using_clauses, int parent)
471                 {
472                         if ((document == null) || (using_clauses == null))
473                                 throw new NullReferenceException ();
474                         if (!(document is SourceFile))
475                                 throw new ArgumentException ();
476
477                         SourceFile source_info = (SourceFile) document;
478
479                         return source_info.DefineNamespace (name, using_clauses, parent);
480                 }
481
482                 public void OpenNamespace (string name)
483                 {
484                         throw new NotSupportedException ();
485                 }
486
487                 public int OpenScope (int startOffset)
488                 {
489                         if (current_method == null)
490                                 return 0;
491
492                         current_method.StartBlock (startOffset);
493                         return 0;
494                 }
495
496                 public void CloseScope (int endOffset)
497                 {
498                         if (current_method == null)
499                                 return;
500
501                         current_method.EndBlock (endOffset);
502                 }
503
504                 public void SetScopeRange (int scopeID, int startOffset, int endOffset)
505                 {
506                         throw new NotSupportedException ();
507                 }
508
509                 public void SetSymAttribute (SymbolToken parent, string name, byte[] data)
510                 {
511                         throw new NotSupportedException ();
512                 }
513
514                 public void SetUnderlyingWriter (IntPtr underlyingWriter)
515                 {
516                         throw new NotSupportedException ();
517                 }
518
519                 public void SetUserEntryPoint (SymbolToken entryMethod)
520                 {
521                         throw new NotSupportedException ();
522                 }
523
524                 public void UsingNamespace (string fullName)
525                 {
526                         throw new NotSupportedException ();
527                 }
528
529                 //
530                 // MonoSymbolWriter implementation
531                 //
532                 protected void DoFixups (Assembly assembly)
533                 {
534                         foreach (SourceMethod method in methods) {
535                                 if (method._method_base is MethodBuilder) {
536                                         MethodBuilder mb = (MethodBuilder) method._method_base;
537                                         method._token = mb.GetToken ().Token;
538                                 } else if (method._method_base is ConstructorBuilder) {
539                                         ConstructorBuilder cb = (ConstructorBuilder) method._method_base;
540                                         method._token = cb.GetToken ().Token;
541                                 } else
542                                         throw new NotSupportedException ();
543
544                                 if (method.SourceFile == null)
545                                         orphant_methods.Add (method);
546                         }
547                 }
548
549                 protected byte[] CreateOutput (Assembly assembly)
550                 {
551                         foreach (SourceMethod method in Methods) {
552                                 if (!method.HasSource) {
553                                         Console.WriteLine ("INGORING METHOD: {0}", method);
554                                         continue;
555                                 }
556
557                                 method.SourceFile.DefineMethod (
558                                         method.MethodBase, method.Token, method.Locals,
559                                         method.Lines, method.Blocks, method.Start.Row, method.End.Row,
560                                         method.NamespaceID);
561                         }
562
563                         return file.CreateSymbolFile ();
564                 }
565         }
566 }
567