Merge pull request #347 from JamesB7/master
[mono.git] / mcs / class / Mono.CompilerServices.SymbolWriter / SourceMethodBuilder.cs
1 //
2 // SourceMethodBuilder.cs
3 //
4 // Authors:
5 //   Martin Baulig (martin@ximian.com)
6 //   Marek Safar (marek.safar@gmail.com)
7 //
8 // (C) 2002 Ximian, Inc.  http://www.ximian.com
9 // Copyright (C) 2012 Xamarin Inc (http://www.xamarin.com)
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 using System.Collections.Generic;
32
33 namespace Mono.CompilerServices.SymbolWriter
34 {
35         public class SourceMethodBuilder
36         {
37                 List<LocalVariableEntry> _locals;
38                 List<CodeBlockEntry> _blocks;
39                 List<ScopeVariable> _scope_vars;
40 #if NET_2_1
41                 System.Collections.Stack _block_stack;
42 #else           
43                 Stack<CodeBlockEntry> _block_stack;
44 #endif
45                 readonly List<LineNumberEntry> method_lines;
46
47                 readonly ICompileUnit _comp_unit;
48                 readonly int ns_id;
49                 readonly IMethodDef method;
50
51                 public SourceMethodBuilder (ICompileUnit comp_unit)
52                 {
53                         this._comp_unit = comp_unit;
54                         method_lines = new List<LineNumberEntry> ();
55                 }
56
57                 public SourceMethodBuilder (ICompileUnit comp_unit, int ns_id, IMethodDef method)
58                         : this (comp_unit)
59                 {
60                         this.ns_id = ns_id;
61                         this.method = method;
62                 }
63
64                 public void MarkSequencePoint (int offset, SourceFileEntry file, int line, int column, bool is_hidden)
65                 {
66                         int file_idx = file != null ? file.Index : 0;
67                         var lne = new LineNumberEntry (file_idx, line, column, offset, is_hidden);
68
69                         if (method_lines.Count > 0) {
70                                 var prev = method_lines[method_lines.Count - 1];
71
72                                 //
73                                 // Same offset cannot be used for multiple lines
74                                 // 
75                                 if (prev.Offset == offset) {
76                                         //
77                                         // Use the new location because debugger will adjust
78                                         // the breakpoint to next line with sequence point
79                                         //
80                                         if (LineNumberEntry.LocationComparer.Default.Compare (lne, prev) > 0)
81                                                 method_lines[method_lines.Count - 1] = lne;
82
83                                         return;
84                                 }
85                         }
86
87                         method_lines.Add (lne);
88                 }
89
90                 public void StartBlock (CodeBlockEntry.Type type, int start_offset)
91                 {
92                         if (_block_stack == null) {
93 #if NET_2_1
94                                 _block_stack = new System.Collections.Stack ();
95 #else                           
96                                 _block_stack = new Stack<CodeBlockEntry> ();
97 #endif
98                         }
99                         
100                         if (_blocks == null)
101                                 _blocks = new List<CodeBlockEntry> ();
102
103                         int parent = CurrentBlock != null ? CurrentBlock.Index : -1;
104
105                         CodeBlockEntry block = new CodeBlockEntry (
106                                 _blocks.Count + 1, parent, type, start_offset);
107
108                         _block_stack.Push (block);
109                         _blocks.Add (block);
110                 }
111
112                 public void EndBlock (int end_offset)
113                 {
114                         CodeBlockEntry block = (CodeBlockEntry) _block_stack.Pop ();
115                         block.Close (end_offset);
116                 }
117
118                 public CodeBlockEntry[] Blocks {
119                         get {
120                                 if (_blocks == null)
121                                         return new CodeBlockEntry [0];
122
123                                 CodeBlockEntry[] retval = new CodeBlockEntry [_blocks.Count];
124                                 _blocks.CopyTo (retval, 0);
125                                 return retval;
126                         }
127                 }
128
129                 public CodeBlockEntry CurrentBlock {
130                         get {
131                                 if ((_block_stack != null) && (_block_stack.Count > 0))
132                                         return (CodeBlockEntry) _block_stack.Peek ();
133                                 else
134                                         return null;
135                         }
136                 }
137
138                 public LocalVariableEntry[] Locals {
139                         get {
140                                 if (_locals == null)
141                                         return new LocalVariableEntry [0];
142                                 else {
143                                         return _locals.ToArray ();
144                                 }
145                         }
146                 }
147
148                 public ICompileUnit SourceFile {
149                         get {
150                                 return _comp_unit;
151                         }
152                 }
153
154                 public void AddLocal (int index, string name)
155                 {
156                         if (_locals == null)
157                                 _locals = new List<LocalVariableEntry> ();
158                         int block_idx = CurrentBlock != null ? CurrentBlock.Index : 0;
159                         _locals.Add (new LocalVariableEntry (index, name, block_idx));
160                 }
161
162                 public ScopeVariable[] ScopeVariables {
163                         get {
164                                 if (_scope_vars == null)
165                                         return new ScopeVariable [0];
166
167                                 return _scope_vars.ToArray ();
168                         }
169                 }
170
171                 public void AddScopeVariable (int scope, int index)
172                 {
173                         if (_scope_vars == null)
174                                 _scope_vars = new List<ScopeVariable> ();
175                         _scope_vars.Add (
176                                 new ScopeVariable (scope, index));
177                 }
178
179                 public void DefineMethod (MonoSymbolFile file)
180                 {
181                         DefineMethod (file, method.Token);
182                 }
183
184                 public void DefineMethod (MonoSymbolFile file, int token)
185                 {
186                         MethodEntry entry = new MethodEntry (
187                                 file, _comp_unit.Entry, token, ScopeVariables,
188                                 Locals, method_lines.ToArray (), Blocks, null, MethodEntry.Flags.ColumnsInfoIncluded, ns_id);
189
190                         file.AddMethod (entry);
191                 }
192         }
193 }