Skip to content

Commit 2ba67bc

Browse files
committed
Moving invocation methods to separate file
1 parent 962fb01 commit 2ba67bc

File tree

5 files changed

+343
-330
lines changed

5 files changed

+343
-330
lines changed

Mono.Debugger.Soft/Mono.Debugger.Soft.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
<Compile Include="Mono.Debugger.Soft\InterfaceMappingMirror.cs" />
7171
<Compile Include="Mono.Debugger.Soft\InvalidStackFrameException.cs" />
7272
<Compile Include="Mono.Debugger.Soft\InvocationException.cs" />
73+
<Compile Include="Mono.Debugger.Soft\InvocationsAPI.cs" />
7374
<Compile Include="Mono.Debugger.Soft\InvokeOptions.cs" />
7475
<Compile Include="Mono.Debugger.Soft\ITargetProcess.cs" />
7576
<Compile Include="Mono.Debugger.Soft\LocalVariable.cs" />
Lines changed: 337 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,337 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
6+
namespace Mono.Debugger.Soft
7+
{
8+
/// <summary>
9+
/// A bunch of extension methods to <see cref="IInvocableMethodOwnerMirror"/> to perform invocations on objects
10+
/// </summary>
11+
public static class InvocationsAPI
12+
{
13+
public static Value InvokeMethod (this IInvocableMethodOwnerMirror mirror, ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options = InvokeOptions.None) {
14+
return InvokeMethod (mirror, mirror.VirtualMachine, thread, method, mirror.GetThisObject (), arguments, options);
15+
}
16+
17+
[Obsolete ("Use the overload without the 'vm' argument")]
18+
public static IAsyncResult BeginInvokeMethod (this IInvocableMethodOwnerMirror mirror, VirtualMachine vm, ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options, AsyncCallback callback, object state) {
19+
return BeginInvokeMethod (vm, thread, method, mirror.GetThisObject (), arguments, options, callback, state);
20+
}
21+
22+
public static IAsyncResult BeginInvokeMethod (this IInvocableMethodOwnerMirror mirror, ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options, AsyncCallback callback, object state) {
23+
return BeginInvokeMethod (mirror.VirtualMachine, thread, method, mirror.GetThisObject (), arguments, options, callback, state);
24+
}
25+
26+
public static Value EndInvokeMethod (this IInvocableMethodOwnerMirror mirror, IAsyncResult asyncResult) {
27+
return EndInvokeMethodInternal (mirror, asyncResult);
28+
}
29+
30+
public static InvokeResult EndInvokeMethodWithResult (this IInvocableMethodOwnerMirror mirror, IAsyncResult asyncResult) {
31+
return EndInvokeMethodInternalWithResult (mirror, asyncResult);
32+
}
33+
34+
public static Task<Value> InvokeMethodAsync (this IInvocableMethodOwnerMirror mirror, ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options = InvokeOptions.None) {
35+
var tcs = new TaskCompletionSource<Value> ();
36+
BeginInvokeMethod (mirror, thread, method, arguments, options, iar =>
37+
{
38+
try {
39+
tcs.SetResult (EndInvokeMethod (mirror, iar));
40+
} catch (OperationCanceledException) {
41+
tcs.TrySetCanceled ();
42+
} catch (Exception ex) {
43+
tcs.TrySetException (ex);
44+
}
45+
}, null);
46+
return tcs.Task;
47+
}
48+
49+
public static Task<InvokeResult> InvokeMethodAsyncWithResult (this IInvocableMethodOwnerMirror mirror, ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options = InvokeOptions.None) {
50+
var tcs = new TaskCompletionSource<InvokeResult> ();
51+
BeginInvokeMethod (mirror, thread, method, arguments, options, iar =>
52+
{
53+
try {
54+
tcs.SetResult (EndInvokeMethodInternalWithResult (mirror, iar));
55+
} catch (OperationCanceledException) {
56+
tcs.TrySetCanceled ();
57+
} catch (Exception ex) {
58+
tcs.TrySetException (ex);
59+
}
60+
}, null);
61+
return tcs.Task;
62+
}
63+
64+
/// <summary>
65+
/// 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
66+
/// finished. The callback will be called with a different IAsyncResult that represents one method invocation.
67+
/// From protocol version 2.22.
68+
/// </summary>
69+
public static IAsyncResult BeginInvokeMultiple (this IInvocableMethodOwnerMirror mirror, ThreadMirror thread, MethodMirror[] methods, IList<IList<Value>> arguments, InvokeOptions options, AsyncCallback callback, object state) {
70+
return BeginInvokeMultiple (mirror.VirtualMachine, thread, methods, mirror.GetThisObject (), arguments, options, callback, state);
71+
}
72+
73+
public static void EndInvokeMultiple (IAsyncResult asyncResult) {
74+
EndInvokeMultipleInternal (asyncResult);
75+
}
76+
77+
/*
78+
* Common implementation for invokes
79+
*/
80+
81+
class InvokeAsyncResult : IInvokeAsyncResult {
82+
83+
public object AsyncState {
84+
get; set;
85+
}
86+
87+
public WaitHandle AsyncWaitHandle {
88+
get; set;
89+
}
90+
91+
public bool CompletedSynchronously {
92+
get {
93+
return false;
94+
}
95+
}
96+
97+
public bool IsCompleted {
98+
get; set;
99+
}
100+
101+
public AsyncCallback Callback {
102+
get; set;
103+
}
104+
105+
public ErrorCode ErrorCode {
106+
get; set;
107+
}
108+
109+
public VirtualMachine VM {
110+
get; set;
111+
}
112+
113+
public ThreadMirror Thread {
114+
get; set;
115+
}
116+
117+
public ValueImpl Value {
118+
get; set;
119+
}
120+
121+
public ValueImpl OutThis {
122+
get; set;
123+
}
124+
125+
public ValueImpl[] OutArgs {
126+
get; set;
127+
}
128+
129+
public ValueImpl Exception {
130+
get; set;
131+
}
132+
133+
public int ID {
134+
get; set;
135+
}
136+
137+
public bool IsMultiple {
138+
get; set;
139+
}
140+
141+
public int NumPending;
142+
143+
public void Abort ()
144+
{
145+
if (ID == 0) // Ooops
146+
return;
147+
148+
AbortInvoke (VM, Thread, ID);
149+
}
150+
}
151+
152+
static IInvokeAsyncResult BeginInvokeMethod (VirtualMachine vm, ThreadMirror thread, MethodMirror method, Value this_obj, IList<Value> arguments, InvokeOptions options, AsyncCallback callback, object state) {
153+
if (thread == null)
154+
throw new ArgumentNullException ("thread");
155+
if (method == null)
156+
throw new ArgumentNullException ("method");
157+
if (arguments == null)
158+
arguments = new Value [0];
159+
160+
InvokeFlags f = InvokeFlags.NONE;
161+
162+
if ((options & InvokeOptions.DisableBreakpoints) != 0)
163+
f |= InvokeFlags.DISABLE_BREAKPOINTS;
164+
if ((options & InvokeOptions.SingleThreaded) != 0)
165+
f |= InvokeFlags.SINGLE_THREADED;
166+
if ((options & InvokeOptions.ReturnOutThis) != 0)
167+
f |= InvokeFlags.OUT_THIS;
168+
if ((options & InvokeOptions.ReturnOutArgs) != 0)
169+
f |= InvokeFlags.OUT_ARGS;
170+
if ((options & InvokeOptions.Virtual) != 0)
171+
f |= InvokeFlags.VIRTUAL;
172+
173+
InvokeAsyncResult r = new InvokeAsyncResult { AsyncState = state, AsyncWaitHandle = new ManualResetEvent (false), VM = vm, Thread = thread, Callback = callback };
174+
thread.InvalidateFrames ();
175+
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);
176+
177+
return r;
178+
}
179+
180+
// This is called when the result of an invoke is received
181+
static void InvokeCB (ValueImpl v, ValueImpl exc, ValueImpl out_this, ValueImpl[] out_args, ErrorCode error, object state) {
182+
InvokeAsyncResult r = (InvokeAsyncResult)state;
183+
184+
if (error != 0) {
185+
r.ErrorCode = error;
186+
} else {
187+
r.Value = v;
188+
r.Exception = exc;
189+
}
190+
191+
r.OutThis = out_this;
192+
r.OutArgs = out_args;
193+
194+
r.IsCompleted = true;
195+
((ManualResetEvent)r.AsyncWaitHandle).Set ();
196+
197+
if (r.Callback != null)
198+
r.Callback.BeginInvoke (r, null, null);
199+
}
200+
201+
static InvokeResult EndInvokeMethodInternalWithResult (IInvocableMethodOwnerMirror mirror, IAsyncResult asyncResult) {
202+
var result = EndInvokeMethodInternalWithResultImpl (asyncResult);
203+
mirror.ProcessResult (result);
204+
return result;
205+
}
206+
207+
static InvokeResult EndInvokeMethodInternalWithResultImpl (IAsyncResult asyncResult) {
208+
if (asyncResult == null)
209+
throw new ArgumentNullException ("asyncResult");
210+
211+
InvokeAsyncResult r = (InvokeAsyncResult)asyncResult;
212+
213+
if (!r.IsCompleted)
214+
r.AsyncWaitHandle.WaitOne ();
215+
216+
if (r.ErrorCode != 0) {
217+
try {
218+
r.VM.ErrorHandler (null, new ErrorHandlerEventArgs () { ErrorCode = r.ErrorCode });
219+
} catch (CommandException ex) {
220+
if (ex.ErrorCode == ErrorCode.INVALID_ARGUMENT)
221+
throw new ArgumentException ("Incorrect number or types of arguments", "arguments");
222+
223+
throw;
224+
}
225+
throw new NotImplementedException ();
226+
} else {
227+
if (r.Exception != null)
228+
throw new InvocationException ((ObjectMirror)r.VM.DecodeValue (r.Exception));
229+
230+
Value out_this = null;
231+
if (r.OutThis != null)
232+
out_this = r.VM.DecodeValue (r.OutThis);
233+
Value[] out_args = null;
234+
if (r.OutArgs != null)
235+
out_args = r.VM.DecodeValues (r.OutArgs);
236+
237+
return new InvokeResult () { Result = r.VM.DecodeValue (r.Value), OutThis = out_this, OutArgs = out_args };
238+
}
239+
}
240+
241+
static Value EndInvokeMethodInternal (IInvocableMethodOwnerMirror mirror, IAsyncResult asyncResult) {
242+
InvokeResult res = EndInvokeMethodInternalWithResult (mirror, asyncResult);
243+
return res.Result;
244+
}
245+
246+
static void EndInvokeMultipleInternal (IAsyncResult asyncResult) {
247+
if (asyncResult == null)
248+
throw new ArgumentNullException ("asyncResult");
249+
250+
InvokeAsyncResult r = (InvokeAsyncResult)asyncResult;
251+
252+
if (!r.IsCompleted)
253+
r.AsyncWaitHandle.WaitOne ();
254+
}
255+
256+
static Value InvokeMethod (IInvocableMethodOwnerMirror mirror, VirtualMachine vm, ThreadMirror thread, MethodMirror method, Value this_obj, IList<Value> arguments, InvokeOptions options) {
257+
return EndInvokeMethodInternal (mirror, BeginInvokeMethod (vm, thread, method, this_obj, arguments, options, null, null));
258+
}
259+
260+
static void AbortInvoke (VirtualMachine vm, ThreadMirror thread, int id)
261+
{
262+
vm.conn.VM_AbortInvoke (thread.Id, id);
263+
}
264+
265+
//
266+
// Implementation of InvokeMultiple
267+
//
268+
269+
static IInvokeAsyncResult BeginInvokeMultiple (VirtualMachine vm, ThreadMirror thread, MethodMirror[] methods, Value this_obj, IList<IList<Value>> arguments, InvokeOptions options, AsyncCallback callback, object state) {
270+
if (thread == null)
271+
throw new ArgumentNullException ("thread");
272+
if (methods == null)
273+
throw new ArgumentNullException ("methods");
274+
foreach (var m in methods)
275+
if (m == null)
276+
throw new ArgumentNullException ("method");
277+
if (arguments == null) {
278+
arguments = new List<IList<Value>> ();
279+
for (int i = 0; i < methods.Length; ++i)
280+
arguments.Add (new Value [0]);
281+
} else {
282+
// FIXME: Not needed for property evaluation
283+
throw new NotImplementedException ();
284+
}
285+
if (callback == null)
286+
throw new ArgumentException ("A callback argument is required for this method.", "callback");
287+
288+
InvokeFlags f = InvokeFlags.NONE;
289+
290+
if ((options & InvokeOptions.DisableBreakpoints) != 0)
291+
f |= InvokeFlags.DISABLE_BREAKPOINTS;
292+
if ((options & InvokeOptions.SingleThreaded) != 0)
293+
f |= InvokeFlags.SINGLE_THREADED;
294+
295+
InvokeAsyncResult r = new InvokeAsyncResult { AsyncState = state, AsyncWaitHandle = new ManualResetEvent (false), VM = vm, Thread = thread, Callback = callback, NumPending = methods.Length, IsMultiple = true };
296+
297+
var mids = new long [methods.Length];
298+
for (int i = 0; i < methods.Length; ++i)
299+
mids [i] = methods [i].Id;
300+
var args = new List<ValueImpl[]> ();
301+
for (int i = 0; i < methods.Length; ++i)
302+
args.Add (vm.EncodeValues (arguments [i]));
303+
thread.InvalidateFrames ();
304+
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);
305+
306+
return r;
307+
}
308+
309+
// This is called when the result of an invoke is received
310+
static void InvokeMultipleCB (ValueImpl v, ValueImpl exc, ValueImpl out_this, ValueImpl[] out_args, ErrorCode error, object state) {
311+
var r = (InvokeAsyncResult)state;
312+
313+
Interlocked.Decrement (ref r.NumPending);
314+
315+
if (error != 0)
316+
r.ErrorCode = error;
317+
318+
if (r.NumPending == 0) {
319+
r.IsCompleted = true;
320+
((ManualResetEvent)r.AsyncWaitHandle).Set ();
321+
}
322+
323+
// Have to pass another asyncresult to the callback since multiple threads can execute it concurrently with results of multiple invocations
324+
var r2 = new InvokeAsyncResult { AsyncState = r.AsyncState, AsyncWaitHandle = null, VM = r.VM, Thread = r.Thread, Callback = r.Callback, IsCompleted = true };
325+
326+
if (error != 0) {
327+
r2.ErrorCode = error;
328+
} else {
329+
r2.Value = v;
330+
r2.Exception = exc;
331+
}
332+
333+
r.Callback.BeginInvoke (r2, null, null);
334+
}
335+
336+
}
337+
}

0 commit comments

Comments
 (0)