2 using System.Collections.Generic;
3 using System.Runtime.Remoting.Messaging;
4 using System.Threading;
6 using System.Threading.Tasks;
9 namespace Mono.Debugger.Soft
11 public class ObjectMirror : Value {
13 AppDomainMirror domain;
15 internal ObjectMirror (VirtualMachine vm, long id) : base (vm, id) {
18 internal ObjectMirror (VirtualMachine vm, long id, TypeMirror type, AppDomainMirror domain) : base (vm, id) {
24 var info = vm.conn.Object_GetInfo (id);
25 type = vm.GetType (info.type_id);
26 domain = vm.GetDomain (info.domain_id);
29 public TypeMirror Type {
32 if (vm.conn.Version.AtLeast (2, 5))
35 type = vm.GetType (vm.conn.Object_GetType (id));
41 public AppDomainMirror Domain {
44 if (vm.conn.Version.AtLeast (2, 5))
47 domain = vm.GetDomain (vm.conn.Object_GetDomain (id));
53 public bool IsCollected {
55 return vm.conn.Object_IsCollected (id);
59 public Value GetValue (FieldInfoMirror field) {
60 return GetValues (new FieldInfoMirror [] { field }) [0];
63 public Value[] GetValues (IList<FieldInfoMirror> fields) {
65 throw new ArgumentNullException ("fields");
66 foreach (FieldInfoMirror f in fields) {
68 throw new ArgumentNullException ("field");
71 long[] ids = new long [fields.Count];
72 for (int i = 0; i < fields.Count; ++i)
73 ids [i] = fields [i].Id;
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");
86 public void SetValues (IList<FieldInfoMirror> fields, Value[] values) {
88 throw new ArgumentNullException ("fields");
90 throw new ArgumentNullException ("values");
91 foreach (FieldInfoMirror f in fields) {
93 throw new ArgumentNullException ("field");
96 foreach (Value v in values) {
98 throw new ArgumentNullException ("values");
101 long[] ids = new long [fields.Count];
102 for (int i = 0; i < fields.Count; ++i)
103 ids [i] = fields [i].Id;
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");
116 public void SetValue (FieldInfoMirror field, Value value) {
117 SetValues (new FieldInfoMirror [] { field }, new Value [] { value });
121 * The current address of the object. It can change during garbage
122 * collections. Use a long since the debuggee might have a different
125 public long Address {
127 return vm.conn.Object_GetAddress (id);
131 public Value InvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments) {
132 return InvokeMethod (vm, thread, method, this, arguments, InvokeOptions.None);
135 public Value InvokeMethod (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options) {
136 return InvokeMethod (vm, thread, method, this, arguments, options);
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);
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);
148 public Value EndInvokeMethod (IAsyncResult asyncResult) {
149 return EndInvokeMethodInternal (asyncResult);
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 =>
158 tcs.SetResult (EndInvokeMethod (iar));
159 } catch (OperationCanceledException) {
160 tcs.TrySetCanceled ();
161 } catch (Exception ex) {
162 tcs.TrySetException (ex);
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.
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);
178 public void EndInvokeMultiple (IAsyncResult asyncResult) {
179 EndInvokeMultipleInternal (asyncResult);
183 * Common implementation for invokes
186 class InvokeAsyncResult : IInvokeAsyncResult {
188 public object AsyncState {
192 public WaitHandle AsyncWaitHandle {
196 public bool CompletedSynchronously {
202 public bool IsCompleted {
206 public AsyncCallback Callback {
210 public ErrorCode ErrorCode {
214 public VirtualMachine VM {
218 public ThreadMirror Thread {
222 public ValueImpl Value {
226 public ValueImpl Exception {
234 public bool IsMultiple {
238 public int NumPending;
242 if (ID == 0) // Ooops
245 ObjectMirror.AbortInvoke (VM, Thread, ID);
249 internal static IInvokeAsyncResult BeginInvokeMethod (VirtualMachine vm, ThreadMirror thread, MethodMirror method, Value this_obj, IList<Value> arguments, InvokeOptions options, AsyncCallback callback, object state) {
251 throw new ArgumentNullException ("thread");
253 throw new ArgumentNullException ("method");
254 if (arguments == null)
255 arguments = new Value [0];
257 InvokeFlags f = InvokeFlags.NONE;
259 if ((options & InvokeOptions.DisableBreakpoints) != 0)
260 f |= InvokeFlags.DISABLE_BREAKPOINTS;
261 if ((options & InvokeOptions.SingleThreaded) != 0)
262 f |= InvokeFlags.SINGLE_THREADED;
264 InvokeAsyncResult r = new InvokeAsyncResult { AsyncState = state, AsyncWaitHandle = new ManualResetEvent (false), VM = vm, Thread = thread, Callback = callback };
265 thread.InvalidateFrames ();
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);
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;
282 r.IsCompleted = true;
283 ((ManualResetEvent)r.AsyncWaitHandle).Set ();
285 if (r.Callback != null)
286 r.Callback.BeginInvoke (r, null, null);
289 internal static Value EndInvokeMethodInternal (IAsyncResult asyncResult) {
290 if (asyncResult == null)
291 throw new ArgumentNullException ("asyncResult");
293 InvokeAsyncResult r = (InvokeAsyncResult)asyncResult;
296 r.AsyncWaitHandle.WaitOne ();
298 if (r.ErrorCode != 0) {
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");
307 throw new NotImplementedException ();
309 if (r.Exception != null)
310 throw new InvocationException ((ObjectMirror)r.VM.DecodeValue (r.Exception));
312 return r.VM.DecodeValue (r.Value);
316 internal static void EndInvokeMultipleInternal (IAsyncResult asyncResult) {
317 if (asyncResult == null)
318 throw new ArgumentNullException ("asyncResult");
320 InvokeAsyncResult r = (InvokeAsyncResult)asyncResult;
323 r.AsyncWaitHandle.WaitOne ();
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));
330 internal static void AbortInvoke (VirtualMachine vm, ThreadMirror thread, int id)
332 vm.conn.VM_AbortInvoke (thread.Id, id);
336 // Implementation of InvokeMultiple
339 internal static IInvokeAsyncResult BeginInvokeMultiple (VirtualMachine vm, ThreadMirror thread, MethodMirror[] methods, Value this_obj, IList<IList<Value>> arguments, InvokeOptions options, AsyncCallback callback, object state) {
341 throw new ArgumentNullException ("thread");
343 throw new ArgumentNullException ("methods");
344 foreach (var m in methods)
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]);
352 // FIXME: Not needed for property evaluation
353 throw new NotImplementedException ();
355 if (callback == null)
356 throw new ArgumentException ("A callback argument is required for this method.", "callback");
358 InvokeFlags f = InvokeFlags.NONE;
360 if ((options & InvokeOptions.DisableBreakpoints) != 0)
361 f |= InvokeFlags.DISABLE_BREAKPOINTS;
362 if ((options & InvokeOptions.SingleThreaded) != 0)
363 f |= InvokeFlags.SINGLE_THREADED;
365 InvokeAsyncResult r = new InvokeAsyncResult { AsyncState = state, AsyncWaitHandle = new ManualResetEvent (false), VM = vm, Thread = thread, Callback = callback, NumPending = methods.Length, IsMultiple = true };
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 thread.InvalidateFrames ();
374 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);
379 // This is called when the result of an invoke is received
380 static void InvokeMultipleCB (ValueImpl v, ValueImpl exc, ErrorCode error, object state) {
381 var r = (InvokeAsyncResult)state;
383 Interlocked.Decrement (ref r.NumPending);
385 if (r.NumPending == 0) {
386 r.IsCompleted = true;
387 ((ManualResetEvent)r.AsyncWaitHandle).Set ();
390 // Have to pass another asyncresult to the callback since multiple threads can execute it concurrently with results of multiple invocations
391 var r2 = new InvokeAsyncResult { AsyncState = r.AsyncState, AsyncWaitHandle = null, VM = r.VM, Thread = r.Thread, Callback = r.Callback, IsCompleted = true };
394 r2.ErrorCode = error;
400 r.Callback.BeginInvoke (r2, null, null);