Merge pull request #3796 from ntherning/windows-backend-for-MemoryMappedFile
[mono.git] / mcs / class / Mono.CompilerServices.SymbolWriter / SourceMethodBuilder.cs
index b45bf8a1fb54d430a31c4c40001db0feff26d40f..816fb68dc5fc3bcbc9fb8669317cfd8e68fb3166 100644 (file)
@@ -28,6 +28,7 @@
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
+using System;
 using System.Collections.Generic;
 
 namespace Mono.CompilerServices.SymbolWriter
@@ -37,11 +38,7 @@ namespace Mono.CompilerServices.SymbolWriter
                List<LocalVariableEntry> _locals;
                List<CodeBlockEntry> _blocks;
                List<ScopeVariable> _scope_vars;
-#if NET_2_1
-               System.Collections.Stack _block_stack;
-#else          
                Stack<CodeBlockEntry> _block_stack;
-#endif
                readonly List<LineNumberEntry> method_lines;
 
                readonly ICompileUnit _comp_unit;
@@ -62,9 +59,14 @@ namespace Mono.CompilerServices.SymbolWriter
                }
 
                public void MarkSequencePoint (int offset, SourceFileEntry file, int line, int column, bool is_hidden)
+               {
+                       MarkSequencePoint (offset, file, line, column, -1, -1, is_hidden);
+               }
+
+               public void MarkSequencePoint (int offset, SourceFileEntry file, int line, int column, int end_line, int end_column, bool is_hidden)
                {
                        int file_idx = file != null ? file.Index : 0;
-                       var lne = new LineNumberEntry (file_idx, line, column, offset, is_hidden);
+                       var lne = new LineNumberEntry (file_idx, line, column, end_line, end_column, offset, is_hidden);
 
                        if (method_lines.Count > 0) {
                                var prev = method_lines[method_lines.Count - 1];
@@ -88,13 +90,14 @@ namespace Mono.CompilerServices.SymbolWriter
                }
 
                public void StartBlock (CodeBlockEntry.Type type, int start_offset)
+               {
+                       StartBlock (type, start_offset, _blocks == null ? 1 : _blocks.Count + 1);
+               }
+
+               public void StartBlock (CodeBlockEntry.Type type, int start_offset, int scopeIndex)
                {
                        if (_block_stack == null) {
-#if NET_2_1
-                               _block_stack = new System.Collections.Stack ();
-#else                          
                                _block_stack = new Stack<CodeBlockEntry> ();
-#endif
                        }
                        
                        if (_blocks == null)
@@ -103,7 +106,7 @@ namespace Mono.CompilerServices.SymbolWriter
                        int parent = CurrentBlock != null ? CurrentBlock.Index : -1;
 
                        CodeBlockEntry block = new CodeBlockEntry (
-                               _blocks.Count + 1, parent, type, start_offset);
+                               scopeIndex, parent, type, start_offset);
 
                        _block_stack.Push (block);
                        _blocks.Add (block);
@@ -183,9 +186,59 @@ namespace Mono.CompilerServices.SymbolWriter
 
                public void DefineMethod (MonoSymbolFile file, int token)
                {
-                       MethodEntry entry = new MethodEntry (
+                       var blocks = Blocks;
+                       if (blocks.Length > 0) {
+                               //
+                               // When index is provided by user it can be inserted in
+                               // any order but mdb format does not store its value. It
+                               // uses stored order as the index instead.
+                               //
+                               var sorted = new List<CodeBlockEntry> (blocks.Length);
+                               int max_index = 0;
+                               for (int i = 0; i < blocks.Length; ++i) {
+                                       max_index = System.Math.Max (max_index, blocks [i].Index);
+                               }
+
+                               for (int i = 0; i < max_index; ++i) {
+                                       var scope_index = i + 1;
+
+                                       //
+                                       // Common fast path
+                                       //
+                                       if (i < blocks.Length && blocks [i].Index == scope_index) {
+                                               sorted.Add (blocks [i]);
+                                               continue;
+                                       }
+
+                                       bool found = false;
+                                       for (int ii = 0; ii < blocks.Length; ++ii) {
+                                               if (blocks [ii].Index == scope_index) {
+                                                       sorted.Add (blocks [ii]);
+                                                       found = true;
+                                                       break;
+                                               }
+                                       }
+
+                                       if (found)
+                                               continue;
+
+                                       //
+                                       // Ideally this should never happen but with current design we can
+                                       // generate scope index for unreachable code before reachable code
+                                       //
+                                       sorted.Add (new CodeBlockEntry (scope_index, -1, CodeBlockEntry.Type.CompilerGenerated, 0));
+                               }
+
+                               blocks = sorted.ToArray ();
+                               //for (int i = 0; i < blocks.Length; ++i) {
+                               //      if (blocks [i].Index - 1 != i)
+                               //                      throw new ArgumentException ("CodeBlocks cannot be converted to mdb format");
+                               //}
+                       }
+
+                       var entry = new MethodEntry (
                                file, _comp_unit.Entry, token, ScopeVariables,
-                               Locals, method_lines.ToArray (), Blocks, null, MethodEntry.Flags.ColumnsInfoIncluded, ns_id);
+                               Locals, method_lines.ToArray (), blocks, null, MethodEntry.Flags.ColumnsInfoIncluded, ns_id);
 
                        file.AddMethod (entry);
                }