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