//
-// System.Diagnostics.SymbolStore/MonoSymbolWriter.cs
+// Mono.CSharp.Debugger/MonoSymbolWriter.cs
//
// Author:
-// Martin Baulig (martin@gnome.org)
+// Martin Baulig (martin@ximian.com)
//
// This is the default implementation of the System.Diagnostics.SymbolStore.ISymbolWriter
// interface.
// (C) 2002 Ximian, Inc. http://www.ximian.com
//
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
using System;
-using System.Reflection;
-using System.Reflection.Emit;
using System.Runtime.CompilerServices;
-using System.Diagnostics.SymbolStore;
using System.Collections;
using System.IO;
-namespace Mono.CSharp.Debugger
+namespace Mono.CompilerServices.SymbolWriter
{
- internal class SourceFile : ISymbolDocumentWriter
+ public interface ISourceFile
{
- private ArrayList _methods = new ArrayList ();
- private string _file_name;
-
- public SourceFile (string filename)
- {
- this._file_name = filename;
- }
-
- public override string ToString ()
- {
- return _file_name;
- }
-
- public string FileName {
- get {
- return _file_name;
- }
- }
-
- public SourceMethod[] Methods {
- get {
- SourceMethod[] retval = new SourceMethod [_methods.Count];
- _methods.CopyTo (retval);
- return retval;
- }
- }
-
- public void AddMethod (SourceMethod method)
- {
- _methods.Add (method);
- }
-
- void ISymbolDocumentWriter.SetCheckSum (Guid algorithmId, byte[] checkSum)
- {
- throw new NotSupportedException ();
- }
-
- void ISymbolDocumentWriter.SetSource (byte[] source)
- {
- throw new NotSupportedException ();
+ SourceFileEntry Entry {
+ get;
}
}
- internal class SourceBlock
+ public interface ISourceMethod
{
- static private int next_index;
- private readonly int _index;
-
- public SourceBlock (SourceMethod method, LineNumberEntry start, LineNumberEntry end)
- {
- this._method = method;
- this._start = start;
- this._end = end;
- this._index = ++next_index;
- }
-
- internal SourceBlock (SourceMethod method, int startOffset)
- {
- this._method = method;
- this._start_offset = startOffset;
- this._index = ++next_index;
- }
-
- public override string ToString ()
- {
- return "SourceBlock #" + ID + " (" + Start + " - " + End + ")";
- }
-
- private readonly SourceMethod _method;
- private ArrayList _blocks = new ArrayList ();
- internal LineNumberEntry _start = LineNumberEntry.Null;
- internal LineNumberEntry _end = LineNumberEntry.Null;
- internal int _start_offset, _end_offset;
- bool _has_source;
-
- internal void SetSourceRange (int startLine, int endLine)
- {
- _start = new LineNumberEntry (startLine, _start_offset);
- _end = new LineNumberEntry (endLine, _end_offset);
- _has_source = true;
- }
-
- private ArrayList _locals = new ArrayList ();
-
- public SourceMethod SourceMethod {
- get {
- return _method;
- }
- }
-
- public SourceBlock[] Blocks {
- get {
- SourceBlock[] retval = new SourceBlock [_blocks.Count];
- _blocks.CopyTo (retval);
- return retval;
- }
- }
-
- public void AddBlock (SourceBlock block)
- {
- _blocks.Add (block);
- }
-
- public bool HasSource {
- get {
- return _has_source;
- }
- }
-
- public LineNumberEntry Start {
- get {
- return _start;
- }
- }
-
- public LineNumberEntry End {
- get {
- return _end;
- }
- }
-
- public int ID {
- get {
- return _index;
- }
- }
-
- public LocalVariableEntry[] Locals {
- get {
- LocalVariableEntry[] retval = new LocalVariableEntry [_locals.Count];
- _locals.CopyTo (retval);
- return retval;
- }
- }
-
- public void AddLocal (LocalVariableEntry local)
- {
- _locals.Add (local);
- }
- }
-
- internal class SourceMethod
- {
- private ArrayList _lines = new ArrayList ();
- private ArrayList _blocks = new ArrayList ();
- private Hashtable _block_hash = new Hashtable ();
- private Stack _block_stack = new Stack ();
-
- internal readonly MethodBase _method_base;
- internal SourceFile _source_file;
- internal int _token;
-
- private SourceBlock _implicit_block;
-
- public SourceMethod (MethodBase method_base, SourceFile source_file)
- : this (method_base)
- {
- this._source_file = source_file;
- }
-
- internal SourceMethod (MethodBase method_base)
- {
- this._method_base = method_base;
-
- this._implicit_block = new SourceBlock (this, 0);
- }
-
- public void SetSourceRange (SourceFile sourceFile,
- int startLine, int startColumn,
- int endLine, int endColumn)
- {
- _source_file = sourceFile;
- _implicit_block.SetSourceRange (startLine, endLine);
- }
-
- public void StartBlock (SourceBlock block)
- {
- _block_stack.Push (block);
- }
-
- public void EndBlock (int endOffset) {
- SourceBlock block = (SourceBlock) _block_stack.Pop ();
-
- block._end_offset = endOffset;
-
- if (_block_stack.Count > 0) {
- SourceBlock parent = (SourceBlock) _block_stack.Peek ();
-
- parent.AddBlock (block);
- } else
- _blocks.Add (block);
-
- _block_hash.Add (block.ID, block);
- }
-
- public void SetBlockRange (int BlockID, int startOffset, int endOffset)
- {
- SourceBlock block = (SourceBlock) _block_hash [BlockID];
- block._start_offset = startOffset;
- block._end_offset = endOffset;
- }
-
- public SourceBlock CurrentBlock {
- get {
- if (_block_stack.Count > 0)
- return (SourceBlock) _block_stack.Peek ();
- else
- return _implicit_block;
- }
- }
-
- public LineNumberEntry[] Lines {
- get {
- LineNumberEntry[] retval = new LineNumberEntry [_lines.Count];
- _lines.CopyTo (retval);
- return retval;
- }
- }
-
- public void AddLine (LineNumberEntry line)
- {
- _lines.Add (line);
- }
-
- public SourceBlock[] Blocks {
- get {
- SourceBlock[] retval = new SourceBlock [_blocks.Count];
- _blocks.CopyTo (retval);
- return retval;
- }
- }
-
- public LocalVariableEntry[] Locals {
- get {
- return _implicit_block.Locals;
- }
- }
-
- public void AddLocal (LocalVariableEntry local)
- {
- _implicit_block.AddLocal (local);
- }
-
- public MethodBase MethodBase {
- get {
- return _method_base;
- }
- }
-
- public string FullName {
- get {
- return _method_base.DeclaringType.FullName + "." + _method_base.Name;
- }
- }
-
- public Type ReturnType {
- get {
- if (_method_base is MethodInfo)
- return ((MethodInfo)_method_base).ReturnType;
- else if (_method_base is ConstructorInfo)
- return _method_base.DeclaringType;
- else
- throw new NotSupportedException ();
- }
- }
-
- public ParameterInfo[] Parameters {
- get {
- if (_method_base == null)
- return new ParameterInfo [0];
-
- ParameterInfo [] retval = _method_base.GetParameters ();
- if (retval == null)
- return new ParameterInfo [0];
- else
- return retval;
- }
- }
-
- public SourceFile SourceFile {
- get {
- return _source_file;
- }
- }
-
- public int Token {
- get {
- if (_token != 0)
- return _token;
- else
- throw new NotSupportedException ();
- }
+ string Name {
+ get;
}
- public bool HasSource {
- get {
- return _implicit_block.HasSource && (_source_file != null);
- }
+ int NamespaceID {
+ get;
}
- public LineNumberEntry Start {
- get {
- return _implicit_block.Start;
- }
- }
-
- public LineNumberEntry End {
- get {
- return _implicit_block.End;
- }
+ int Token {
+ get;
}
}
- public class MonoSymbolWriter : IMonoSymbolWriter
+ public class MonoSymbolWriter
{
- protected ModuleBuilder module_builder;
protected ArrayList locals = null;
- protected ArrayList orphant_methods = null;
protected ArrayList methods = null;
- protected Hashtable sources = null;
- private ArrayList mbuilder_array = null;
-
- internal SourceMethod[] Methods {
- get {
- SourceMethod[] retval = new SourceMethod [methods.Count];
- methods.CopyTo (retval);
- return retval;
- }
- }
-
- internal SourceFile[] Sources {
+ protected ArrayList sources = null;
+ protected readonly MonoSymbolFile file;
+ private string filename = null;
+
+ LineNumberEntry [] current_method_lines;
+ int current_method_lines_pos = 0;
+
+ internal ISourceFile[] Sources {
get {
- SourceFile[] retval = new SourceFile [sources.Count];
- sources.Values.CopyTo (retval, 0);
+ ISourceFile[] retval = new ISourceFile [sources.Count];
+ sources.CopyTo (retval, 0);
return retval;
}
}
// Interface IMonoSymbolWriter
//
- public MonoSymbolWriter (ModuleBuilder mb, ArrayList mbuilder_array)
+ public MonoSymbolWriter (string filename)
{
- this.module_builder = mb;
this.methods = new ArrayList ();
- this.sources = new Hashtable ();
- this.orphant_methods = new ArrayList ();
+ this.sources = new ArrayList ();
this.locals = new ArrayList ();
- this.mbuilder_array = mbuilder_array;
- }
-
- public void Close ()
- {
- throw new InvalidOperationException ();
- }
+ this.file = new MonoSymbolFile ();
- public byte[] CreateSymbolFile (AssemblyBuilder assembly_builder)
- {
- DoFixups (assembly_builder);
-
- return CreateOutput (assembly_builder);
+ this.filename = filename + ".mdb";
+
+ this.current_method_lines = new LineNumberEntry [50];
}
- public void CloseNamespace () {
- }
+ public void CloseNamespace ()
+ { }
- // Create and return a new IMonoSymbolDocumentWriter.
- public ISymbolDocumentWriter DefineDocument (string url,
- Guid language,
- Guid languageVendor,
- Guid documentType)
- {
- SourceFile source_info = new SourceFile (url);
- sources.Add (url, source_info);
- return source_info;
- }
-
- public void DefineField (
- SymbolToken parent,
- string name,
- FieldAttributes attributes,
- byte[] signature,
- SymAddressKind addrKind,
- int addr1,
- int addr2,
- int addr3)
- {
- throw new NotSupportedException ();
- }
-
- public void DefineGlobalVariable (
- string name,
- FieldAttributes attributes,
- byte[] signature,
- SymAddressKind addrKind,
- int addr1,
- int addr2,
- int addr3)
- {
- throw new NotSupportedException ();
- }
-
- public void DefineLocalVariable (string name,
- FieldAttributes attributes,
- byte[] signature,
- SymAddressKind addrKind,
- int addr1,
- int addr2,
- int addr3,
- int startOffset,
- int endOffset)
+ public void DefineLocalVariable (string name, byte[] signature)
{
if (current_method == null)
return;
- current_method.AddLocal (new LocalVariableEntry (name, attributes, signature));
- }
-
- public void DefineParameter (string name,
- ParameterAttributes attributes,
- int sequence,
- SymAddressKind addrKind,
- int addr1,
- int addr2,
- int addr3)
- {
- throw new NotSupportedException ();
- }
-
- public void DefineSequencePoints (ISymbolDocumentWriter document,
- int[] offsets,
- int[] lines,
- int[] columns,
- int[] endLines,
- int[] endColumns)
- {
- throw new NotSupportedException ();
+ current_method.AddLocal (name, signature);
}
public void MarkSequencePoint (int offset, int line, int column)
if (current_method == null)
return;
- LineNumberEntry source_line = new LineNumberEntry (line, offset);
- current_method.AddLine (source_line);
- }
-
- public void Initialize (IntPtr emitter, string filename, bool fFullBuild)
- {
- throw new NotSupportedException ();
+ if (current_method_lines_pos == current_method_lines.Length) {
+ LineNumberEntry [] tmp = current_method_lines;
+ current_method_lines = new LineNumberEntry [current_method_lines.Length * 2];
+ Array.Copy (tmp, current_method_lines, current_method_lines_pos);
+ }
+
+ current_method_lines [current_method_lines_pos++] = new LineNumberEntry (line, offset);
}
- public void OpenMethod (SymbolToken symbol_token)
+ public void OpenMethod (ISourceFile file, ISourceMethod method,
+ int startRow, int startColumn,
+ int endRow, int endColumn)
{
- int token = symbol_token.GetToken ();
-
- if ((token & 0xff000000) != 0x06000000)
- throw new ArgumentException ();
-
- int index = (token & 0xffffff) - 1;
-
- MethodBase mb = (MethodBase) mbuilder_array [index];
-
- current_method = new SourceMethod (mb);
+ SourceMethod source = new SourceMethod (
+ file, method, startRow, startColumn, endRow, endColumn);
+ current_method = source;
methods.Add (current_method);
}
- public void SetMethodSourceRange (ISymbolDocumentWriter startDoc,
- int startLine, int startColumn,
- ISymbolDocumentWriter endDoc,
- int endLine, int endColumn)
+ public void CloseMethod ()
{
- if (current_method == null)
- return;
- if ((startDoc == null) || (endDoc == null))
- throw new NullReferenceException ();
- if (!(startDoc is SourceFile) || !(endDoc is SourceFile))
- throw new ArgumentException ("both startDoc and endDoc must be created " +
- "with DefineDocument()");
- if (!startDoc.Equals (endDoc))
- throw new ArgumentException ("startDoc and endDoc must be the same");
-
- SourceFile source_info = (SourceFile) startDoc;
-
- current_method.SetSourceRange (source_info, startLine, startColumn,
- endLine, endColumn);
-
- source_info.AddMethod (current_method);
+ current_method.SetLineNumbers (
+ current_method_lines, current_method_lines_pos);
+ current_method_lines_pos = 0;
+
+ current_method = null;
}
- public void CloseMethod () {
- current_method = null;
+ public SourceFileEntry DefineDocument (string url)
+ {
+ SourceFileEntry entry = new SourceFileEntry (file, url);
+ sources.Add (entry);
+ return entry;
}
- public void OpenNamespace (string name)
+ public int DefineNamespace (string name, SourceFileEntry source,
+ string[] using_clauses, int parent)
{
- throw new NotSupportedException ();
+ if ((source == null) || (using_clauses == null))
+ throw new NullReferenceException ();
+
+ return source.DefineNamespace (name, using_clauses, parent);
}
public int OpenScope (int startOffset)
if (current_method == null)
return 0;
- SourceBlock block = new SourceBlock (current_method, startOffset);
- current_method.StartBlock (block);
-
- return block.ID;
+ current_method.StartBlock (startOffset);
+ return 0;
}
- public void CloseScope (int endOffset) {
+ public void CloseScope (int endOffset)
+ {
if (current_method == null)
return;
current_method.EndBlock (endOffset);
}
- public void SetScopeRange (int scopeID, int startOffset, int endOffset)
+ protected byte[] CreateOutput (Guid guid)
{
- if (current_method == null)
- return;
+ foreach (SourceMethod method in methods) {
+ method.SourceFile.Entry.DefineMethod (
+ method.Method.Name, method.Method.Token,
+ method.Locals, method.Lines, method.Blocks,
+ method.Start.Row, method.End.Row,
+ method.Method.NamespaceID);
+ }
- current_method.SetBlockRange (scopeID, startOffset, endOffset);
+ return file.CreateSymbolFile (guid);
}
- public void SetSymAttribute (SymbolToken parent, string name, byte[] data)
+ public void WriteSymbolFile (Guid guid)
{
- throw new NotSupportedException ();
+ using (FileStream stream = new FileStream (
+ filename, FileMode.Create, FileAccess.Write)) {
+ byte[] data = CreateOutput (guid);
+ stream.Write (data, 0, data.Length);
+ }
}
- public void SetUnderlyingWriter (IntPtr underlyingWriter)
+ protected class SourceMethod
{
- throw new NotSupportedException ();
- }
+ LineNumberEntry [] lines;
+ private ArrayList _locals;
+ private ArrayList _blocks;
+ private Stack _block_stack;
+ private int next_block_id = 0;
+ private ISourceMethod _method;
+ private ISourceFile _file;
+ private LineNumberEntry _start, _end;
- public void SetUserEntryPoint (SymbolToken entryMethod)
- {
- throw new NotSupportedException ();
- }
+ private LexicalBlockEntry _implicit_block;
- public void UsingNamespace (string fullName)
- {
- throw new NotSupportedException ();
- }
+ public SourceMethod (ISourceFile file, ISourceMethod method,
+ int startLine, int startColumn,
+ int endLine, int endColumn)
+ {
+ this._file = file;
+ this._method = method;
- //
- // MonoSymbolWriter implementation
- //
- protected void DoFixups (Assembly assembly)
- {
- foreach (SourceMethod method in methods) {
- if (method._method_base is MethodBuilder) {
- MethodBuilder mb = (MethodBuilder) method._method_base;
- method._token = mb.GetToken ().Token;
- } else if (method._method_base is ConstructorBuilder) {
- ConstructorBuilder cb = (ConstructorBuilder) method._method_base;
- method._token = cb.GetToken ().Token;
- } else
- throw new NotSupportedException ();
-
- if (method.SourceFile == null)
- orphant_methods.Add (method);
+ this._start = new LineNumberEntry (startLine, 0);
+ this._end = new LineNumberEntry (endLine, 0);
+
+ this._implicit_block = new LexicalBlockEntry (0, 0);
}
- }
- protected byte[] CreateOutput (Assembly assembly)
- {
- MonoSymbolFile file = new MonoSymbolFile ();
+ public void StartBlock (int startOffset)
+ {
+ LexicalBlockEntry block = new LexicalBlockEntry (
+ ++next_block_id, startOffset);
+ if (_block_stack == null)
+ _block_stack = new Stack ();
+ _block_stack.Push (block);
+ if (_blocks == null)
+ _blocks = new ArrayList ();
+ _blocks.Add (block);
+ }
- foreach (SourceMethod method in Methods) {
- if (!method.HasSource) {
- Console.WriteLine ("INGORING METHOD: {0}", method);
- continue;
+ public void EndBlock (int endOffset)
+ {
+ LexicalBlockEntry block =
+ (LexicalBlockEntry) _block_stack.Pop ();
+
+ block.Close (endOffset);
+ }
+
+ public LexicalBlockEntry[] Blocks {
+ get {
+ if (_blocks == null)
+ return new LexicalBlockEntry [0];
+ else {
+ LexicalBlockEntry[] retval =
+ new LexicalBlockEntry [_blocks.Count];
+ _blocks.CopyTo (retval, 0);
+ return retval;
+ }
}
+ }
- SourceFileEntry source = file.DefineSource (method.SourceFile.FileName);
+ public LexicalBlockEntry CurrentBlock {
+ get {
+ if ((_block_stack != null) && (_block_stack.Count > 0))
+ return (LexicalBlockEntry) _block_stack.Peek ();
+ else
+ return _implicit_block;
+ }
+ }
- source.DefineMethod (method.MethodBase, method.Token, method.Locals,
- method.Lines, method.Start.Row, method.End.Row);
+ public LineNumberEntry[] Lines {
+ get {
+ return lines;
+ }
}
- return file.CreateSymbolFile ();
+ public LocalVariableEntry[] Locals {
+ get {
+ if (_locals == null)
+ return new LocalVariableEntry [0];
+ else {
+ LocalVariableEntry[] retval =
+ new LocalVariableEntry [_locals.Count];
+ _locals.CopyTo (retval, 0);
+ return retval;
+ }
+ }
+ }
+
+ public void AddLocal (string name, byte[] signature)
+ {
+ if (_locals == null)
+ _locals = new ArrayList ();
+ _locals.Add (new LocalVariableEntry (
+ name, signature, CurrentBlock.Index));
+ }
+
+ public ISourceFile SourceFile {
+ get { return _file; }
+ }
+
+ public ISourceMethod Method {
+ get { return _method; }
+ }
+
+ public LineNumberEntry Start {
+ get { return _start; }
+ }
+
+ public LineNumberEntry End {
+ get { return _end; }
+ }
+
+ //
+ // Passes on the lines from the MonoSymbolWriter. This method is
+ // free to mutate the lns array, and it does.
+ //
+ internal void SetLineNumbers (LineNumberEntry [] lns, int count)
+ {
+ int pos = 0;
+
+ int last_offset = -1;
+ int last_row = -1;
+ for (int i = 0; i < count; i++) {
+ LineNumberEntry line = lns [i];
+
+ if (line.Offset > last_offset) {
+ if (last_row >= 0)
+ lns [pos++] = new LineNumberEntry (
+ last_row, last_offset);
+
+ last_row = line.Row;
+ last_offset = line.Offset;
+ } else if (line.Row > last_row) {
+ last_row = line.Row;
+ }
+ }
+
+ lines = new LineNumberEntry [count + ((last_row >= 0) ? 1 : 0)];
+ Array.Copy (lns, lines, pos);
+ if (last_row >= 0)
+ lines [pos] = new LineNumberEntry (
+ last_row, last_offset);
+ }
}
}
}
-