Add [Category ("NotWorking")] to failing test.
[mono.git] / mcs / class / Mono.Debugger.Soft / Mono.Debugger.Soft / ObjectMirror.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Runtime.Remoting.Messaging;
4 using System.Threading;
5
6 namespace Mono.Debugger.Soft
7 {
8         public class ObjectMirror : Value {
9                 TypeMirror type;
10                 AppDomainMirror domain;
11         
12                 internal ObjectMirror (VirtualMachine vm, long id) : base (vm, id) {
13                 }
14         
15                 internal ObjectMirror (VirtualMachine vm, long id, TypeMirror type, AppDomainMirror domain) : base (vm, id) {
16                         this.type = type;
17                         this.domain = domain;
18                 }
19
20                 void GetInfo () {
21                         var info = vm.conn.Object_GetInfo (id);
22                         type = vm.GetType (info.type_id);
23                         domain = vm.GetDomain (info.domain_id);
24                 }
25
26                 public TypeMirror Type {
27                         get {
28                                 if (type == null) {
29                                         if (vm.conn.Version.AtLeast (2, 5))
30                                                 GetInfo ();
31                                         else
32                                                 type = vm.GetType (vm.conn.Object_GetType (id));
33                                 }
34                                 return type;
35                         }
36                 }
37
38                 public AppDomainMirror Domain {
39                         get {
40                                 if (domain == null) {
41                                         if (vm.conn.Version.AtLeast (2, 5))
42                                                 GetInfo ();
43                                         else
44                                                 domain = vm.GetDomain (vm.conn.Object_GetDomain (id));
45                                 }
46                                 return domain;
47                         }
48                 }
49
50                 public bool IsCollected {
51                         get {
52                                 return vm.conn.Object_IsCollected (id);
53                         }
54                 }
55
56                 public Value GetValue (FieldInfoMirror field) {
57                         return GetValues (new FieldInfoMirror [] { field }) [0];
58                 }
59
60                 public Value[] GetValues (IList<FieldInfoMirror> fields) {
61                         if (fields == null)
62                                 throw new ArgumentNullException ("fields");
63                         foreach (FieldInfoMirror f in fields) {
64                                 if (f == null)
65                                         throw new ArgumentNullException ("field");
66                                 CheckMirror (f);
67                         }
68                         long[] ids = new long [fields.Count];
69                         for (int i = 0; i < fields.Count; ++i)
70                                 ids [i] = fields [i].Id;
71                         try {
72                                 return vm.DecodeValues (vm.conn.Object_GetValues (id, ids));
73                         } catch (CommandException ex) {
74                                 if (ex.ErrorCode == ErrorCode.INVALID_FIELDID)
75                                         throw new ArgumentException ("One of the fields is not valid for this type.", "fields");
76                                 else
77                                         throw;
78                         }
79                 }
80
81                 public void SetValues (IList<FieldInfoMirror> fields, Value[] values) {
82                         if (fields == null)
83                                 throw new ArgumentNullException ("fields");
84                         if (values == null)
85                                 throw new ArgumentNullException ("values");
86                         foreach (FieldInfoMirror f in fields) {
87                                 if (f == null)
88                                         throw new ArgumentNullException ("field");
89                                 CheckMirror (f);
90                         }
91                         foreach (Value v in values) {
92                                 if (v == null)
93                                         throw new ArgumentNullException ("values");
94                                 CheckMirror (v);
95                         }
96                         long[] ids = new long [fields.Count];
97                         for (int i = 0; i < fields.Count; ++i)
98                                 ids [i] = fields [i].Id;
99                         try {
100                                 vm.conn.Object_SetValues (id, ids, vm.EncodeValues (values));
101                         } catch (CommandException ex) {
102                                 if (ex.ErrorCode == ErrorCode.INVALID_FIELDID)
103                                         throw new ArgumentException ("One of the fields is not valid for this type.", "fields");
104                                 else if (ex.ErrorCode == ErrorCode.INVALID_ARGUMENT)
105                                         throw new ArgumentException ("One of the values is not valid for its field.", "values");
106                                 else
107                                         throw;
108                         }
109                 }
110
111                 public void SetValue (FieldInfoMirror field, Value value) {
112                         SetValues (new FieldInfoMirror [] { field }, new Value [] { value });
113                 }
114
115                 /*
116                  * The current address of the object. It can change during garbage 
117                  * collections. Use a long since the debuggee might have a different 
118                  * pointer size. 
119                  */
120                 public long Address {
121                         get {
122                                 return vm.conn.Object_GetAddress (id);
123                         }
124                 }
125
126                 public Value InvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments) {
127                         return InvokeMethod (vm, thread, method, this, arguments, InvokeOptions.None);
128                 }
129
130                 public Value InvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options) {
131                         return InvokeMethod (vm, thread, method, this, arguments, options);
132                 }
133
134                 [Obsolete ("Use the overload without the 'vm' argument")]
135                 public IAsyncResult BeginInvokeMethod (VirtualMachine vm, ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options, AsyncCallback callback, object state) {
136                         return BeginInvokeMethod (vm, thread, method, this, arguments, options, callback, state);
137                 }
138
139                 public IAsyncResult BeginInvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options, AsyncCallback callback, object state) {
140                         return BeginInvokeMethod (vm, thread, method, this, arguments, options, callback, state);
141                 }
142
143                 public Value EndInvokeMethod (IAsyncResult asyncResult) {
144                         return EndInvokeMethodInternal (asyncResult);
145                 }
146
147                 //
148                 // Invoke the members of METHODS one-by-one, calling CALLBACK after each invoke was finished. The IAsyncResult will be marked as completed after all invokes have
149                 // finished. The callback will be called with a different IAsyncResult that represents one method invocation.
150                 // From protocol version 2.22.
151                 //
152                 public IAsyncResult BeginInvokeMultiple (ThreadMirror thread, MethodMirror[] methods, IList<IList<Value>> arguments, InvokeOptions options, AsyncCallback callback, object state) {
153                         return BeginInvokeMultiple (vm, thread, methods, this, arguments, options, callback, state);
154                 }
155
156                 public void EndInvokeMultiple (IAsyncResult asyncResult) {
157                         EndInvokeMultipleInternal (asyncResult);
158                 }
159
160                 /*
161                  * Common implementation for invokes
162                  */
163
164                 class InvokeAsyncResult : IInvokeAsyncResult {
165
166                         public object AsyncState {
167                                 get; set;
168                         }
169
170                         public WaitHandle AsyncWaitHandle {
171                                 get; set;
172                         }
173
174                         public bool CompletedSynchronously {
175                                 get {
176                                         return false;
177                                 }
178                         }
179
180                         public bool IsCompleted {
181                                 get; set;
182                         }
183
184                         public AsyncCallback Callback {
185                                 get; set;
186                         }
187
188                         public ErrorCode ErrorCode {
189                                 get; set;
190                         }
191
192                         public VirtualMachine VM {
193                                 get; set;
194                         }
195
196                         public ThreadMirror Thread {
197                                 get; set;
198                         }
199
200                         public ValueImpl Value {
201                                 get; set;
202                         }
203
204                         public ValueImpl Exception {
205                                 get; set;
206                         }
207
208                         public int ID {
209                                 get; set;
210                         }
211
212                         public bool IsMultiple {
213                                 get; set;
214                         }
215                            
216                         public int NumPending;
217
218                         public void Abort ()
219                         {
220                                 if (ID == 0) // Ooops
221                                         return;
222
223                                 ObjectMirror.AbortInvoke (VM, Thread, ID);
224                         }
225                 }
226
227                 internal static IInvokeAsyncResult BeginInvokeMethod (VirtualMachine vm, ThreadMirror thread, MethodMirror method, Value this_obj, IList<Value> arguments, InvokeOptions options, AsyncCallback callback, object state) {
228                         if (thread == null)
229                                 throw new ArgumentNullException ("thread");
230                         if (method == null)
231                                 throw new ArgumentNullException ("method");
232                         if (arguments == null)
233                                 arguments = new Value [0];
234
235                         InvokeFlags f = InvokeFlags.NONE;
236
237                         if ((options & InvokeOptions.DisableBreakpoints) != 0)
238                                 f |= InvokeFlags.DISABLE_BREAKPOINTS;
239                         if ((options & InvokeOptions.SingleThreaded) != 0)
240                                 f |= InvokeFlags.SINGLE_THREADED;
241
242                         InvokeAsyncResult r = new InvokeAsyncResult { AsyncState = state, AsyncWaitHandle = new ManualResetEvent (false), VM = vm, Thread = thread, Callback = callback };
243
244                         r.ID = vm.conn.VM_BeginInvokeMethod (thread.Id, method.Id, this_obj != null ? vm.EncodeValue (this_obj) : vm.EncodeValue (vm.CreateValue (null)), vm.EncodeValues (arguments), f, InvokeCB, r);
245
246                         return r;
247                 }
248
249                 // This is called when the result of an invoke is received
250                 static void InvokeCB (ValueImpl v, ValueImpl exc, ErrorCode error, object state) {
251                         InvokeAsyncResult r = (InvokeAsyncResult)state;
252
253                         if (error != 0) {
254                                 r.ErrorCode = error;
255                         } else {
256                                 r.Value = v;
257                                 r.Exception = exc;
258                         }
259
260                         r.IsCompleted = true;
261                         ((ManualResetEvent)r.AsyncWaitHandle).Set ();
262
263                         if (r.Callback != null)
264                                 r.Callback.BeginInvoke (r, null, null);
265                 }
266
267             internal static Value EndInvokeMethodInternal (IAsyncResult asyncResult) {
268                         if (asyncResult == null)
269                                 throw new ArgumentNullException ("asyncResult");
270
271                         InvokeAsyncResult r = (InvokeAsyncResult)asyncResult;
272
273                         if (!r.IsCompleted)
274                                 r.AsyncWaitHandle.WaitOne ();
275
276                         if (r.ErrorCode != 0) {
277                                 try {
278                                         r.VM.ErrorHandler (null, new ErrorHandlerEventArgs () { ErrorCode = r.ErrorCode });
279                                 } catch (CommandException ex) {
280                                         if (ex.ErrorCode == ErrorCode.INVALID_ARGUMENT)
281                                                 throw new ArgumentException ("Incorrect number or types of arguments", "arguments");
282                                         else
283                                                 throw;
284                                 }
285                                 throw new NotImplementedException ();
286                         } else {
287                                 if (r.Exception != null)
288                                         throw new InvocationException ((ObjectMirror)r.VM.DecodeValue (r.Exception));
289                                 else
290                                         return r.VM.DecodeValue (r.Value);
291                         }
292                 }
293
294             internal static void EndInvokeMultipleInternal (IAsyncResult asyncResult) {
295                         if (asyncResult == null)
296                                 throw new ArgumentNullException ("asyncResult");
297
298                         InvokeAsyncResult r = (InvokeAsyncResult)asyncResult;
299
300                         if (!r.IsCompleted)
301                                 r.AsyncWaitHandle.WaitOne ();
302                 }
303
304                 internal static Value InvokeMethod (VirtualMachine vm, ThreadMirror thread, MethodMirror method, Value this_obj, IList<Value> arguments, InvokeOptions options) {
305                         return EndInvokeMethodInternal (BeginInvokeMethod (vm, thread, method, this_obj, arguments, options, null, null));
306                 }
307
308                 internal static void AbortInvoke (VirtualMachine vm, ThreadMirror thread, int id)
309                 {
310                         vm.conn.VM_AbortInvoke (thread.Id, id);
311                 }
312
313                 //
314                 // Implementation of InvokeMultiple
315                 //
316
317                 internal static IInvokeAsyncResult BeginInvokeMultiple (VirtualMachine vm, ThreadMirror thread, MethodMirror[] methods, Value this_obj, IList<IList<Value>> arguments, InvokeOptions options, AsyncCallback callback, object state) {
318                         if (thread == null)
319                                 throw new ArgumentNullException ("thread");
320                         if (methods == null)
321                                 throw new ArgumentNullException ("methods");
322                         foreach (var m in methods)
323                                 if (m == null)
324                                         throw new ArgumentNullException ("method");
325                         if (arguments == null) {
326                                 arguments = new List<IList<Value>> ();
327                                 for (int i = 0; i < methods.Length; ++i)
328                                         arguments.Add (new Value [0]);
329                         } else {
330                                 // FIXME: Not needed for property evaluation
331                                 throw new NotImplementedException ();
332                         }
333                         if (callback == null)
334                                 throw new ArgumentException ("A callback argument is required for this method.", "callback");
335
336                         InvokeFlags f = InvokeFlags.NONE;
337
338                         if ((options & InvokeOptions.DisableBreakpoints) != 0)
339                                 f |= InvokeFlags.DISABLE_BREAKPOINTS;
340                         if ((options & InvokeOptions.SingleThreaded) != 0)
341                                 f |= InvokeFlags.SINGLE_THREADED;
342
343                         InvokeAsyncResult r = new InvokeAsyncResult { AsyncState = state, AsyncWaitHandle = new ManualResetEvent (false), VM = vm, Thread = thread, Callback = callback, NumPending = methods.Length, IsMultiple = true };
344
345                         var mids = new long [methods.Length];
346                         for (int i = 0; i < methods.Length; ++i)
347                                 mids [i] = methods [i].Id;
348                         var args = new List<ValueImpl[]> ();
349                         for (int i = 0; i < methods.Length; ++i)
350                                 args.Add (vm.EncodeValues (arguments [i]));
351                         r.ID = vm.conn.VM_BeginInvokeMethods (thread.Id, mids, this_obj != null ? vm.EncodeValue (this_obj) : vm.EncodeValue (vm.CreateValue (null)), args, f, InvokeMultipleCB, r);
352
353                         return r;
354                 }
355
356                 // This is called when the result of an invoke is received
357                 static void InvokeMultipleCB (ValueImpl v, ValueImpl exc, ErrorCode error, object state) {
358                         var r = (InvokeAsyncResult)state;
359
360                         Interlocked.Decrement (ref r.NumPending);
361
362                         if (r.NumPending == 0) {
363                                 r.IsCompleted = true;
364                                 ((ManualResetEvent)r.AsyncWaitHandle).Set ();
365                         }
366
367                         // Have to pass another asyncresult to the callback since multiple threads can execute it concurrently with results of multiple invocations
368                         var r2 = new InvokeAsyncResult { AsyncState = r.AsyncState, AsyncWaitHandle = null, VM = r.VM, Thread = r.Thread, Callback = r.Callback, IsCompleted = true };
369
370                         if (error != 0) {
371                                 r2.ErrorCode = error;
372                         } else {
373                                 r2.Value = v;
374                                 r2.Exception = exc;
375                         }
376
377                         r.Callback.BeginInvoke (r2, null, null);
378                 }
379         }
380 }