[jit] Always cache the latest image set in case of a cache miss.
[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                                 if (domain == null) {
39                                         if (vm.Version.AtLeast (2, 38)) {
40                                                 try {
41                                                         domain = vm.GetDomain (vm.conn.StackFrame_GetDomain (thread.Id, Id));
42                                                 } catch (AbsentInformationException) {
43                                                         domain = Thread.Domain;
44                                                 }
45                                         } else {
46                                                 domain = Thread.Domain;
47                                         }
48                                 }
49
50                                 return domain;
51                         }
52                 }
53
54                 public MethodMirror Method {
55                         get {
56                                 return method;
57                         }
58                 }
59
60                 public Location Location {
61                         get {
62                                 if (location == null) {
63                                         int line_number;
64                                         string src_file = null;
65                                         byte[] hash = null;
66                                         int column_number = 0;
67                                         int end_line_number = -1;
68                                         int end_column_number = -1;
69
70                                         if (il_offset == -1)
71                                                 line_number = -1;
72                                         else
73                                                 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);
74
75                                         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);
76                                 }
77                                 return location;
78                         }
79                 }
80
81                 public string FileName {
82                         get {
83                                 return Location.SourceFile;
84                         }
85                 }
86
87                 public int ILOffset {
88                         get {
89                                 return Location.ILOffset;
90                         }
91                 }
92
93                 public int LineNumber {
94                         get {
95                                 return Location.LineNumber;
96                         }
97                 }
98
99                 public int ColumnNumber {
100                         get {
101                                 return Location.ColumnNumber;
102                         }
103                 }
104
105                 public bool IsDebuggerInvoke {
106                         get {
107                                 return (flags & StackFrameFlags.DEBUGGER_INVOKE) != 0;
108                         }
109                 }
110
111                 /*
112                  * Whenever this frame transitions to native code. The method associated
113                  * with the frame is either an InternalCall or a pinvoke method.
114                  */
115                 public bool IsNativeTransition {
116                         get {
117                                 return (flags & StackFrameFlags.NATIVE_TRANSITION) != 0;
118                         }
119                 }
120
121                 public Value GetValue (ParameterInfoMirror param) {
122                         if (param == null)
123                                 throw new ArgumentNullException ("param");
124                         if (param.Method != Method)
125                                 throw new ArgumentException ("Parameter doesn't belong to this frame's method.");
126                         if (param.IsRetval)
127                                 throw new ArgumentException ("Parameter represents the method return value.");
128
129                         // FIXME: Liveness
130                         // FIXME: Allow returning the frame return value if possible
131                         return vm.DecodeValue (vm.conn.StackFrame_GetValues (thread.Id, Id, new int [] { (- param.Position) - 1 })[0]);
132                 }
133
134                 public Value GetValue (LocalVariable var) {
135                         if (var == null)
136                                 throw new ArgumentNullException ("var");
137                         if (var.Method != Method)
138                                 throw new ArgumentException ("Local variable doesn't belong to this frame's method.");
139
140                         // FIXME: Liveness
141                         // FIXME: Check for return value
142                         // FIXME: Allow returning the frame return value if possible
143                         return vm.DecodeValue (vm.conn.StackFrame_GetValues (thread.Id, Id, new int [] { var.GetValueIndex } )[0]);
144                 }
145
146                 public Value[] GetValues (LocalVariable[] vars) {
147                         if (vars == null)
148                                 throw new ArgumentNullException ("vars");
149                         for (int i = 0; i < vars.Length; ++i) {
150                                 if (vars [i] == null)
151                                         throw new ArgumentNullException ("vars");
152                                 if (vars [i].Method != Method)
153                                         throw new ArgumentException ("Local variable doesn't belong to this frame's method.");
154                         }
155                         int[] pos = new int [vars.Length];
156                         for (int i = 0; i < vars.Length; ++i)
157                                 pos [i] = vars [i].GetValueIndex;
158                         return vm.DecodeValues (vm.conn.StackFrame_GetValues (thread.Id, Id, pos));
159                 }
160
161                 public Value GetArgument (int pos) {
162                         return GetValue (Method.GetParameters () [pos]);
163                 }
164
165                 public Value GetThis () {
166                         return vm.DecodeValue (vm.conn.StackFrame_GetThis (thread.Id, Id));
167                 }
168
169                 // Since protocol version 2.44
170                 public void SetThis (Value value) {
171                         if (value == null)
172                                 throw new ArgumentNullException ("value");
173                         if (Method.IsStatic || !Method.DeclaringType.IsValueType)
174                                 throw new InvalidOperationException ("The frame's method needs to be a valuetype instance method.");
175                         vm.conn.StackFrame_SetThis (thread.Id, Id, vm.EncodeValue (value));
176                 }
177
178                 public void SetValue (LocalVariable var, Value value) {
179                         if (var == null)
180                                 throw new ArgumentNullException ("var");
181                         if (var.Method != Method)
182                                 throw new ArgumentException ("Local variable doesn't belong to this frame's method.");
183                         if (value == null)
184                                 throw new ArgumentNullException ("value");
185                         CheckMirror (value);
186                         // FIXME: Liveness
187                         // FIXME: Check for return value
188                         try {
189                                 vm.conn.StackFrame_SetValues (thread.Id, Id, new int [] { var.GetValueIndex }, new ValueImpl [] { vm.EncodeValue (value) });
190                         } catch (CommandException ex) {
191                                 if (ex.ErrorCode == ErrorCode.INVALID_ARGUMENT)
192                                         throw new ArgumentException ("Value does not match the type of the local variable.");
193                                 else
194                                         throw;
195                         }
196                 }
197
198                 public void SetValue (ParameterInfoMirror param, Value value) {
199                         if (param == null)
200                                 throw new ArgumentNullException ("param");
201                         if (param.Method != Method)
202                                 throw new ArgumentException ("Parameter doesn't belong to this frame's method.");
203                         if (param.IsRetval)
204                                 throw new ArgumentException ("Parameter represents the method return value.");
205                         if (value == null)
206                                 throw new ArgumentNullException ("value");
207                         CheckMirror (value);
208
209                         // FIXME: Liveness
210                         // FIXME: Allow setting the frame return value if possible
211                         try {
212                                 vm.conn.StackFrame_SetValues (thread.Id, Id, new int [] { (- param.Position) - 1 }, new ValueImpl [] { vm.EncodeValue (value) });
213                         } catch (CommandException ex) {
214                                 if (ex.ErrorCode == ErrorCode.INVALID_ARGUMENT)
215                                         throw new ArgumentException ("Value does not match the type of the variable.");
216                                 else
217                                         throw;
218                         }
219                 }
220
221                 public IList<LocalVariable> GetVisibleVariables () {
222                         if (Location.ILOffset == -1)
223                                 throw new AbsentInformationException ();
224
225                         return Method.GetLocals ().Where (l => l.LiveRangeStart <= location.ILOffset && l.LiveRangeEnd >= location.ILOffset).ToList ();
226                 }
227
228                 public LocalVariable GetVisibleVariableByName (string name) {
229                         if (name == null)
230                                 throw new ArgumentNullException ("name");
231
232                         if (Location.ILOffset == -1)
233                                 throw new AbsentInformationException ();
234
235                         return Method.GetLocals ().Where (l => l.LiveRangeStart <= location.ILOffset && l.LiveRangeEnd >= location.ILOffset && l.Name == name).FirstOrDefault ();
236                 }
237     }
238 }