2 // System.Diagnostics.SymbolStore/MonoSymbolWriter.cs
5 // Martin Baulig (martin@gnome.org)
7 // This is the default implementation of the System.Diagnostics.SymbolStore.ISymbolWriter
10 // (C) 2002 Ximian, Inc. http://www.ximian.com
14 using System.Reflection;
15 using System.Reflection.Emit;
16 using System.Runtime.CompilerServices;
17 using System.Diagnostics.SymbolStore;
18 using System.Collections;
21 namespace Mono.CSharp.Debugger
23 internal class SourceFile : SourceFileEntry, ISymbolDocumentWriter
25 private ArrayList _methods = new ArrayList ();
27 public SourceFile (MonoSymbolFile file, string filename)
28 : base (file, filename)
31 public new SourceMethod[] Methods {
33 SourceMethod[] retval = new SourceMethod [_methods.Count];
34 _methods.CopyTo (retval);
39 public void AddMethod (SourceMethod method)
41 _methods.Add (method);
44 void ISymbolDocumentWriter.SetCheckSum (Guid algorithmId, byte[] checkSum)
46 throw new NotSupportedException ();
49 void ISymbolDocumentWriter.SetSource (byte[] source)
51 throw new NotSupportedException ();
55 internal class SourceMethod
57 LineNumberEntry [] lines;
58 private ArrayList _locals;
59 private ArrayList _blocks;
60 private Stack _block_stack;
61 private int next_block_id = 0;
63 internal readonly MethodBase _method_base;
64 internal SourceFile _source_file;
66 private int _namespace_id;
67 private LineNumberEntry _start, _end;
68 private MonoSymbolFile _file;
70 private LexicalBlockEntry _implicit_block;
72 internal SourceMethod (MonoSymbolFile file, SourceFile source_file,
73 int startLine, int startColumn, int endLine, int endColumn,
74 MethodBase method_base, int namespace_id)
77 this._method_base = method_base;
78 this._source_file = source_file;
79 this._namespace_id = namespace_id;
81 this._start = new LineNumberEntry (startLine, 0);
82 this._end = new LineNumberEntry (endLine, 0);
84 this._implicit_block = new LexicalBlockEntry (0, 0);
87 public void StartBlock (int startOffset)
89 LexicalBlockEntry block = new LexicalBlockEntry (++next_block_id, startOffset);
90 if (_block_stack == null)
91 _block_stack = new Stack ();
92 _block_stack.Push (block);
94 _blocks = new ArrayList ();
98 public void EndBlock (int endOffset)
100 LexicalBlockEntry block = (LexicalBlockEntry) _block_stack.Pop ();
102 block.Close (endOffset);
105 public LexicalBlockEntry[] Blocks {
108 return new LexicalBlockEntry [0];
110 LexicalBlockEntry[] retval = new LexicalBlockEntry [_blocks.Count];
111 _blocks.CopyTo (retval, 0);
117 public LexicalBlockEntry CurrentBlock {
119 if ((_block_stack != null) && (_block_stack.Count > 0))
120 return (LexicalBlockEntry) _block_stack.Peek ();
122 return _implicit_block;
126 public LineNumberEntry[] Lines {
132 public LocalVariableEntry[] Locals {
135 return new LocalVariableEntry [0];
137 LocalVariableEntry[] retval = new LocalVariableEntry [_locals.Count];
138 _locals.CopyTo (retval, 0);
144 public void AddLocal (string name, FieldAttributes attributes, byte[] signature)
147 _locals = new ArrayList ();
148 _locals.Add (new LocalVariableEntry (name, attributes, signature, CurrentBlock.Index));
151 public MethodBase MethodBase {
157 public string FullName {
159 return _method_base.DeclaringType.FullName + "." + _method_base.Name;
163 public Type ReturnType {
165 if (_method_base is MethodInfo)
166 return ((MethodInfo)_method_base).ReturnType;
167 else if (_method_base is ConstructorInfo)
168 return _method_base.DeclaringType;
170 throw new NotSupportedException ();
174 public ParameterInfo[] Parameters {
176 if (_method_base == null)
177 return new ParameterInfo [0];
179 ParameterInfo [] retval = _method_base.GetParameters ();
181 return new ParameterInfo [0];
187 public SourceFile SourceFile {
198 throw new NotSupportedException ();
202 public bool HasSource {
204 return _source_file != null;
208 public LineNumberEntry Start {
214 public LineNumberEntry End {
220 public int NamespaceID {
222 return _namespace_id;
227 // Passes on the lines from the MonoSymbolWriter. This method is
228 // free to mutate the lns array, and it does.
230 internal void SetLineNumbers (LineNumberEntry [] lns, int count)
234 int last_offset = -1;
236 for (int i = 0; i < count; i++) {
237 LineNumberEntry line = lns [i];
239 if (line.Offset > last_offset) {
241 lns [pos++] = new LineNumberEntry (last_row, last_offset);
244 last_offset = line.Offset;
245 } else if (line.Row > last_row) {
250 lines = new LineNumberEntry [count + ((last_row >= 0) ? 1 : 0)];
251 Array.Copy (lns, lines, pos);
253 lines [pos] = new LineNumberEntry (last_row, last_offset);
256 LineNumberEntry[] BuildLineNumberTable (LineNumberEntry[] line_numbers)
258 ArrayList list = new ArrayList ();
262 LineNumberEntry[] retval = new LineNumberEntry [list.Count];
263 list.CopyTo (retval, 0);
268 public class MonoSymbolWriter : IMonoSymbolWriter
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;
277 LineNumberEntry [] current_method_lines;
278 int current_method_lines_pos = 0;
280 internal SourceMethod[] Methods {
282 SourceMethod[] retval = new SourceMethod [methods.Count];
283 methods.CopyTo (retval);
288 internal SourceFile[] Sources {
290 SourceFile[] retval = new SourceFile [sources.Count];
291 sources.Values.CopyTo (retval, 0);
296 private SourceMethod current_method = null;
299 // Interface IMonoSymbolWriter
302 public MonoSymbolWriter (ModuleBuilder mb)
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 ();
311 this.current_method_lines = new LineNumberEntry [50];
316 throw new InvalidOperationException ();
319 public byte[] CreateSymbolFile (AssemblyBuilder assembly_builder)
321 DoFixups (assembly_builder);
323 return CreateOutput (assembly_builder);
326 public void CloseNamespace () {
329 // Create and return a new IMonoSymbolDocumentWriter.
330 public ISymbolDocumentWriter DefineDocument (string url,
335 if (sources.ContainsKey (url))
336 return (ISymbolDocumentWriter)sources [url];
337 SourceFile source_info = new SourceFile (file, url);
338 sources.Add (url, source_info);
342 public void DefineField (
345 FieldAttributes attributes,
347 SymAddressKind addrKind,
352 throw new NotSupportedException ();
355 public void DefineGlobalVariable (
357 FieldAttributes attributes,
359 SymAddressKind addrKind,
364 throw new NotSupportedException ();
367 public void DefineLocalVariable (string name,
368 FieldAttributes attributes,
370 SymAddressKind addrKind,
377 if (current_method == null)
380 current_method.AddLocal (name, attributes, signature);
383 public void DefineParameter (string name,
384 ParameterAttributes attributes,
386 SymAddressKind addrKind,
391 throw new NotSupportedException ();
394 public void DefineSequencePoints (ISymbolDocumentWriter document,
401 throw new NotSupportedException ();
404 public void MarkSequencePoint (int offset, int line, int column)
406 if (current_method == null)
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);
415 current_method_lines [current_method_lines_pos++] = new LineNumberEntry (line, offset);
418 public void Initialize (IntPtr emitter, string filename, bool fFullBuild)
420 throw new NotSupportedException ();
423 public void OpenMethod (SymbolToken symbol_token)
425 throw new NotSupportedException ();
428 public void SetMethodSourceRange (ISymbolDocumentWriter startDoc,
429 int startLine, int startColumn,
430 ISymbolDocumentWriter endDoc,
431 int endLine, int endColumn)
433 throw new NotSupportedException ();
436 public void OpenMethod (ISymbolDocumentWriter document, int startLine, int startColumn,
437 int endLine, int endColumn, MethodBase method, int namespace_id)
439 SourceFile source_info = document as SourceFile;
441 if ((source_info == null) || (method == null))
442 throw new NullReferenceException ();
444 current_method = new SourceMethod (file, source_info, startLine, startColumn,
445 endLine, endColumn, method, namespace_id);
447 methods.Add (current_method);
448 source_info.AddMethod (current_method);
451 public void CloseMethod ()
453 current_method.SetLineNumbers (current_method_lines, current_method_lines_pos + 1);
454 current_method_lines_pos = 0;
456 current_method = null;
459 public int DefineNamespace (string name, ISymbolDocumentWriter document,
460 string[] using_clauses, int parent)
462 if ((document == null) || (using_clauses == null))
463 throw new NullReferenceException ();
464 if (!(document is SourceFile))
465 throw new ArgumentException ();
467 SourceFile source_info = (SourceFile) document;
469 return source_info.DefineNamespace (name, using_clauses, parent);
472 public void OpenNamespace (string name)
474 throw new NotSupportedException ();
477 public int OpenScope (int startOffset)
479 if (current_method == null)
482 current_method.StartBlock (startOffset);
486 public void CloseScope (int endOffset)
488 if (current_method == null)
491 current_method.EndBlock (endOffset);
494 public void SetScopeRange (int scopeID, int startOffset, int endOffset)
496 throw new NotSupportedException ();
499 public void SetSymAttribute (SymbolToken parent, string name, byte[] data)
501 throw new NotSupportedException ();
504 public void SetUnderlyingWriter (IntPtr underlyingWriter)
506 throw new NotSupportedException ();
509 public void SetUserEntryPoint (SymbolToken entryMethod)
511 throw new NotSupportedException ();
514 public void UsingNamespace (string fullName)
516 throw new NotSupportedException ();
520 // MonoSymbolWriter implementation
522 protected void DoFixups (Assembly assembly)
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;
532 throw new NotSupportedException ();
534 if (method.SourceFile == null)
535 orphant_methods.Add (method);
539 protected byte[] CreateOutput (Assembly assembly)
541 foreach (SourceMethod method in Methods) {
542 if (!method.HasSource) {
543 Console.WriteLine ("INGORING METHOD: {0}", method);
547 method.SourceFile.DefineMethod (
548 method.MethodBase, method.Token, method.Locals,
549 method.Lines, method.Blocks, method.Start.Row, method.End.Row,
553 return file.CreateSymbolFile ();