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 static LocalVariableEntry [] locals_buf = new LocalVariableEntry [20];
135 public LocalVariableEntry[] Locals {
138 return new LocalVariableEntry [0];
140 LocalVariableEntry[] retval = new LocalVariableEntry [locals_pos];
141 Array.Copy (locals_buf, retval, locals_pos);
147 public void AddLocal (string name, FieldAttributes attributes, byte[] signature)
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);
154 locals_buf [locals_pos ++] = new LocalVariableEntry (name, attributes, signature, CurrentBlock.Index);
157 public MethodBase MethodBase {
163 public string FullName {
165 return _method_base.DeclaringType.FullName + "." + _method_base.Name;
169 public Type ReturnType {
171 if (_method_base is MethodInfo)
172 return ((MethodInfo)_method_base).ReturnType;
173 else if (_method_base is ConstructorInfo)
174 return _method_base.DeclaringType;
176 throw new NotSupportedException ();
180 public ParameterInfo[] Parameters {
182 if (_method_base == null)
183 return new ParameterInfo [0];
185 ParameterInfo [] retval = _method_base.GetParameters ();
187 return new ParameterInfo [0];
193 public SourceFile SourceFile {
204 throw new NotSupportedException ();
208 public bool HasSource {
210 return _source_file != null;
214 public LineNumberEntry Start {
220 public LineNumberEntry End {
226 public int NamespaceID {
228 return _namespace_id;
233 // Passes on the lines from the MonoSymbolWriter. This method is
234 // free to mutate the lns array, and it does.
236 internal void SetLineNumbers (LineNumberEntry [] lns, int count)
240 int last_offset = -1;
242 for (int i = 0; i < count; i++) {
243 LineNumberEntry line = lns [i];
245 if (line.Offset > last_offset) {
247 lns [pos++] = new LineNumberEntry (last_row, last_offset);
250 last_offset = line.Offset;
251 } else if (line.Row > last_row) {
256 lines = new LineNumberEntry [count + ((last_row >= 0) ? 1 : 0)];
257 Array.Copy (lns, lines, pos);
259 lines [pos] = new LineNumberEntry (last_row, last_offset);
263 public class MonoSymbolWriter : IMonoSymbolWriter
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;
272 LineNumberEntry [] current_method_lines;
273 int current_method_lines_pos = 0;
275 internal SourceMethod[] Methods {
277 SourceMethod[] retval = new SourceMethod [methods.Count];
278 methods.CopyTo (retval);
283 internal SourceFile[] Sources {
285 SourceFile[] retval = new SourceFile [sources.Count];
286 sources.Values.CopyTo (retval, 0);
291 private SourceMethod current_method = null;
294 // Interface IMonoSymbolWriter
297 public MonoSymbolWriter (ModuleBuilder mb)
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 ();
306 this.current_method_lines = new LineNumberEntry [50];
311 throw new InvalidOperationException ();
314 public byte[] CreateSymbolFile (AssemblyBuilder assembly_builder)
316 DoFixups (assembly_builder);
318 return CreateOutput (assembly_builder);
321 public void CloseNamespace () {
324 // Create and return a new IMonoSymbolDocumentWriter.
325 public ISymbolDocumentWriter DefineDocument (string url,
330 if (sources.ContainsKey (url))
331 return (ISymbolDocumentWriter)sources [url];
332 SourceFile source_info = new SourceFile (file, url);
333 sources.Add (url, source_info);
337 public void DefineField (
340 FieldAttributes attributes,
342 SymAddressKind addrKind,
347 throw new NotSupportedException ();
350 public void DefineGlobalVariable (
352 FieldAttributes attributes,
354 SymAddressKind addrKind,
359 throw new NotSupportedException ();
362 public void DefineLocalVariable (string name,
363 FieldAttributes attributes,
365 SymAddressKind addrKind,
372 if (current_method == null)
375 current_method.AddLocal (name, attributes, signature);
378 public void DefineParameter (string name,
379 ParameterAttributes attributes,
381 SymAddressKind addrKind,
386 throw new NotSupportedException ();
389 public void DefineSequencePoints (ISymbolDocumentWriter document,
396 throw new NotSupportedException ();
399 public void MarkSequencePoint (int offset, int line, int column)
401 if (current_method == null)
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);
410 current_method_lines [current_method_lines_pos++] = new LineNumberEntry (line, offset);
413 public void Initialize (IntPtr emitter, string filename, bool fFullBuild)
415 throw new NotSupportedException ();
418 public void OpenMethod (SymbolToken symbol_token)
420 throw new NotSupportedException ();
423 public void SetMethodSourceRange (ISymbolDocumentWriter startDoc,
424 int startLine, int startColumn,
425 ISymbolDocumentWriter endDoc,
426 int endLine, int endColumn)
428 throw new NotSupportedException ();
431 public void OpenMethod (ISymbolDocumentWriter document, int startLine, int startColumn,
432 int endLine, int endColumn, MethodBase method, int namespace_id)
434 SourceFile source_info = document as SourceFile;
436 if ((source_info == null) || (method == null))
437 throw new NullReferenceException ();
439 current_method = new SourceMethod (file, source_info, startLine, startColumn,
440 endLine, endColumn, method, namespace_id);
442 methods.Add (current_method);
443 source_info.AddMethod (current_method);
446 public void CloseMethod ()
448 current_method.SetLineNumbers (current_method_lines, current_method_lines_pos);
449 current_method_lines_pos = 0;
451 current_method = null;
454 public int DefineNamespace (string name, ISymbolDocumentWriter document,
455 string[] using_clauses, int parent)
457 if ((document == null) || (using_clauses == null))
458 throw new NullReferenceException ();
459 if (!(document is SourceFile))
460 throw new ArgumentException ();
462 SourceFile source_info = (SourceFile) document;
464 return source_info.DefineNamespace (name, using_clauses, parent);
467 public void OpenNamespace (string name)
469 throw new NotSupportedException ();
472 public int OpenScope (int startOffset)
474 if (current_method == null)
477 current_method.StartBlock (startOffset);
481 public void CloseScope (int endOffset)
483 if (current_method == null)
486 current_method.EndBlock (endOffset);
489 public void SetScopeRange (int scopeID, int startOffset, int endOffset)
491 throw new NotSupportedException ();
494 public void SetSymAttribute (SymbolToken parent, string name, byte[] data)
496 throw new NotSupportedException ();
499 public void SetUnderlyingWriter (IntPtr underlyingWriter)
501 throw new NotSupportedException ();
504 public void SetUserEntryPoint (SymbolToken entryMethod)
506 throw new NotSupportedException ();
509 public void UsingNamespace (string fullName)
511 throw new NotSupportedException ();
515 // MonoSymbolWriter implementation
517 protected void DoFixups (Assembly assembly)
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;
527 throw new NotSupportedException ();
529 if (method.SourceFile == null)
530 orphant_methods.Add (method);
534 protected byte[] CreateOutput (Assembly assembly)
536 foreach (SourceMethod method in Methods) {
537 if (!method.HasSource) {
538 Console.WriteLine ("INGORING METHOD: {0}", method);
542 method.SourceFile.DefineMethod (
543 method.MethodBase, method.Token, method.Locals,
544 method.Lines, method.Blocks, method.Start.Row, method.End.Row,
548 return file.CreateSymbolFile ();