Merge pull request #1319 from directhex/systemwide-per-arch-aot-cache
[mono.git] / mcs / class / Mono.Debugger.Soft / Mono.Debugger.Soft / StackFrame.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4
5 namespace Mono.Debugger.Soft
6 {
7         public class StackFrame : Mirror
8         {
9                 ThreadMirror thread;
10                 AppDomainMirror domain;
11                 MethodMirror method;
12                 int il_offset;
13                 Location location;
14                 StackFrameFlags flags;
15
16                 /*
17                  * FIXME: Decide on the way to request/handle debugging information:
18                  * - request the info in bulk for all frames/on demand for individual frames
19                  * - request the info from the runtime/request only the il offset, and compute
20                  *   everything else based on this info using the method debug info.
21                  */
22
23                 internal StackFrame (VirtualMachine vm, long id, ThreadMirror thread, MethodMirror method, int il_offset, StackFrameFlags flags) : base (vm, id) {
24                         this.thread = thread;
25                         this.method = method;
26                         this.il_offset = il_offset;
27                         this.flags = flags;
28                 }
29
30                 public ThreadMirror Thread {
31                         get {
32                                 return thread;
33                         }
34                 }
35
36                 public AppDomainMirror Domain {
37                         get {
38                                 vm.CheckProtocolVersion (2, 38);
39                                 if (domain == null)
40                                         domain = vm.GetDomain (vm.conn.StackFrame_GetDomain (thread.Id, Id));
41
42                                 return domain;
43                         }
44                 }
45
46                 public MethodMirror Method {
47                         get {
48                                 return method;
49                         }
50                 }
51
52                 public Location Location {
53                         get {
54                                 if (location == null) {
55                                         int line_number;
56                                         string src_file = null;
57                                         byte[] hash = null;
58                                         int column_number = 0;
59                                         int end_line_number = -1;
60                                         int end_column_number = -1;
61
62                                         if (il_offset == -1)
63                                                 line_number = -1;
64                                         else
65                                                 line_number = method.il_offset_to_line_number (il_offset, out src_file, out hash, out column_number, out end_line_number, out end_column_number);
66
67                                         location = new Location (vm, Method, 0, il_offset, src_file != null ? src_file : method.SourceFile, line_number, column_number, end_line_number, end_column_number, hash);
68                                 }
69                                 return location;
70                         }
71                 }
72
73                 public string FileName {
74                         get {
75                                 return Location.SourceFile;
76                         }
77                 }
78
79                 public int ILOffset {
80                         get {
81                                 return Location.ILOffset;
82                         }
83                 }
84
85                 public int LineNumber {
86                         get {
87                                 return Location.LineNumber;
88                         }
89                 }
90
91                 public int ColumnNumber {
92                         get {
93                                 return Location.ColumnNumber;
94                         }
95                 }
96
97                 public bool IsDebuggerInvoke {
98                         get {
99                                 return (flags & StackFrameFlags.DEBUGGER_INVOKE) != 0;
100                         }
101                 }
102
103                 /*
104                  * Whenever this frame transitions to native code. The method associated
105                  * with the frame is either an InternalCall or a pinvoke method.
106                  */
107                 public bool IsNativeTransition {
108                         get {
109                                 return (flags & StackFrameFlags.NATIVE_TRANSITION) != 0;
110                         }
111                 }
112
113                 public Value GetValue (ParameterInfoMirror param) {
114                         if (param == null)
115                                 throw new ArgumentNullException ("param");
116                         if (param.Method != Method)
117                                 throw new ArgumentException ("Parameter doesn't belong to this frame's method.");
118                         if (param.IsRetval)
119                                 throw new ArgumentException ("Parameter represents the method return value.");
120
121                         // FIXME: Liveness
122                         // FIXME: Allow returning the frame return value if possible
123                         return vm.DecodeValue (vm.conn.StackFrame_GetValues (thread.Id, Id, new int [] { (- param.Position) - 1 })[0]);
124                 }
125
126                 public Value GetValue (LocalVariable var) {
127                         if (var == null)
128                                 throw new ArgumentNullException ("var");
129                         if (var.Method != Method)
130                                 throw new ArgumentException ("Local variable doesn't belong to this frame's method.");
131
132                         // FIXME: Liveness
133                         // FIXME: Check for return value
134                         // FIXME: Allow returning the frame return value if possible
135                         return vm.DecodeValue (vm.conn.StackFrame_GetValues (thread.Id, Id, new int [] { var.GetValueIndex } )[0]);
136                 }
137
138                 public Value[] GetValues (LocalVariable[] vars) {
139                         if (vars == null)
140                                 throw new ArgumentNullException ("vars");
141                         for (int i = 0; i < vars.Length; ++i) {
142                                 if (vars [i] == null)
143                                         throw new ArgumentNullException ("vars");
144                                 if (vars [i].Method != Method)
145                                         throw new ArgumentException ("Local variable doesn't belong to this frame's method.");
146                         }
147                         int[] pos = new int [vars.Length];
148                         for (int i = 0; i < vars.Length; ++i)
149                                 pos [i] = vars [i].GetValueIndex;
150                         return vm.DecodeValues (vm.conn.StackFrame_GetValues (thread.Id, Id, pos));
151                 }
152
153                 public Value GetArgument (int pos) {
154                         return GetValue (Method.GetParameters () [pos]);
155                 }
156
157                 public Value GetThis () {
158                         return vm.DecodeValue (vm.conn.StackFrame_GetThis (thread.Id, Id));
159                 }
160
161                 public void SetValue (LocalVariable var, Value value) {
162                         if (var == null)
163                                 throw new ArgumentNullException ("var");
164                         if (var.Method != Method)
165                                 throw new ArgumentException ("Local variable doesn't belong to this frame's method.");
166                         if (value == null)
167                                 throw new ArgumentNullException ("value");
168                         CheckMirror (value);
169                         // FIXME: Liveness
170                         // FIXME: Check for return value
171                         try {
172                                 vm.conn.StackFrame_SetValues (thread.Id, Id, new int [] { var.GetValueIndex }, new ValueImpl [] { vm.EncodeValue (value) });
173                         } catch (CommandException ex) {
174                                 if (ex.ErrorCode == ErrorCode.INVALID_ARGUMENT)
175                                         throw new ArgumentException ("Value does not match the type of the local variable.");
176                                 else
177                                         throw;
178                         }
179                 }
180
181                 public void SetValue (ParameterInfoMirror param, Value value) {
182                         if (param == null)
183                                 throw new ArgumentNullException ("param");
184                         if (param.Method != Method)
185                                 throw new ArgumentException ("Parameter doesn't belong to this frame's method.");
186                         if (param.IsRetval)
187                                 throw new ArgumentException ("Parameter represents the method return value.");
188                         if (value == null)
189                                 throw new ArgumentNullException ("value");
190                         CheckMirror (value);
191
192                         // FIXME: Liveness
193                         // FIXME: Allow setting the frame return value if possible
194                         try {
195                                 vm.conn.StackFrame_SetValues (thread.Id, Id, new int [] { (- param.Position) - 1 }, new ValueImpl [] { vm.EncodeValue (value) });
196                         } catch (CommandException ex) {
197                                 if (ex.ErrorCode == ErrorCode.INVALID_ARGUMENT)
198                                         throw new ArgumentException ("Value does not match the type of the variable.");
199                                 else
200                                         throw;
201                         }
202                 }
203
204                 public IList<LocalVariable> GetVisibleVariables () {
205                         if (Location.ILOffset == -1)
206                                 throw new AbsentInformationException ();
207
208                         return Method.GetLocals ().Where (l => l.LiveRangeStart <= location.ILOffset && l.LiveRangeEnd >= location.ILOffset).ToList ();
209                 }
210
211                 public LocalVariable GetVisibleVariableByName (string name) {
212                         if (name == null)
213                                 throw new ArgumentNullException ("name");
214
215                         if (Location.ILOffset == -1)
216                                 throw new AbsentInformationException ();
217
218                         return Method.GetLocals ().Where (l => l.LiveRangeStart <= location.ILOffset && l.LiveRangeEnd >= location.ILOffset && l.Name == name).FirstOrDefault ();
219                 }
220     }
221 }