NONE = 0x0,
DISABLE_BREAKPOINTS = 0x1,
SINGLE_THREADED = 0x2,
- OUT_THIS = 0x4
+ OUT_THIS = 0x4,
+ OUT_ARGS = 0x8,
}
enum ElementType {
}
}
- internal delegate void InvokeMethodCallback (ValueImpl v, ValueImpl exc, ValueImpl out_this, ErrorCode error, object state);
+ internal delegate void InvokeMethodCallback (ValueImpl v, ValueImpl exc, ValueImpl out_this, ValueImpl[] out_args, ErrorCode error, object state);
+
+ void read_invoke_res (PacketReader r, out ValueImpl v, out ValueImpl exc, out ValueImpl out_this, out ValueImpl[] out_args) {
+ int resflags = r.ReadByte ();
+ v = null;
+ exc = null;
+ out_this = null;
+ out_args = null;
+ if (resflags == 0) {
+ exc = r.ReadValue ();
+ } else {
+ v = r.ReadValue ();
+ if ((resflags & 2) != 0)
+ out_this = r.ReadValue ();
+ if ((resflags & 4) != 0) {
+ int nargs = r.ReadInt ();
+ out_args = new ValueImpl [nargs];
+ for (int i = 0; i < nargs; ++i)
+ out_args [i] = r.ReadValue ();
+ }
+ }
+ }
internal int VM_BeginInvokeMethod (long thread, long method, ValueImpl this_arg, ValueImpl[] arguments, InvokeFlags flags, InvokeMethodCallback callback, object state) {
return Send (CommandSet.VM, (int)CmdVM.INVOKE_METHOD, new PacketWriter ().WriteId (thread).WriteInt ((int)flags).WriteId (method).WriteValue (this_arg).WriteInt (arguments.Length).WriteValues (arguments), delegate (PacketReader r) {
ValueImpl v, exc, out_this = null;
+ ValueImpl[] out_args = null;
if (r.ErrorCode != 0) {
- callback (null, null, null, (ErrorCode)r.ErrorCode, state);
+ callback (null, null, null, null, (ErrorCode)r.ErrorCode, state);
} else {
- int restype = r.ReadByte ();
- if (restype == 0) {
- exc = r.ReadValue ();
- v = null;
- } else if (restype == 1) {
- v = r.ReadValue ();
- exc = null;
- } else if (restype == 2) {
- v = r.ReadValue ();
- out_this = r.ReadValue ();
- exc = null;
- } else {
- throw new NotSupportedException ();
- }
- callback (v, exc, out_this, 0, state);
+ read_invoke_res (r, out v, out exc, out out_this, out out_args);
+ callback (v, exc, out_this, out_args, 0, state);
}
}, 1);
}
}
return Send (CommandSet.VM, (int)CmdVM.INVOKE_METHODS, w, delegate (PacketReader r) {
ValueImpl v, exc, out_this = null;
+ ValueImpl[] out_args = null;
if (r.ErrorCode != 0) {
- callback (null, null, null, (ErrorCode)r.ErrorCode, state);
+ callback (null, null, null, null, (ErrorCode)r.ErrorCode, state);
} else {
- int restype = r.ReadByte ();
- if (restype == 0) {
- exc = r.ReadValue ();
- v = null;
- } else if (restype == 1) {
- v = r.ReadValue ();
- exc = null;
- } else if (restype == 2) {
- v = r.ReadValue ();
- out_this = r.ReadValue ();
- exc = null;
- } else {
- throw new NotSupportedException ();
- }
- callback (v, exc, out_this, 0, state);
+ read_invoke_res (r, out v, out exc, out out_this, out out_args);
+ callback (v, exc, out_this, out_args, 0, state);
}
}, methods.Length);
}
* Return the changed receiver when invoking
* a valuetype method.
*/
- ReturnOutThis = 4
+ ReturnOutThis = 4,
+ /*
+ * Return the values of out arguments
+ */
+ ReturnOutArgs = 8
}
}
// Since protocol version 2.35
//
public Value OutThis { get; set; }
+ //
+ // The value of the arguments after the call
+ // Only set when using the InvokeOptions.ReturnOutArgs flag.
+ // Since protocol version 2.35
+ //
+ public Value[] OutArgs { get; set; }
}
public class ObjectMirror : Value {
}, null);
return tcs.Task;
}
+
+ public Task<InvokeResult> InvokeMethodAsyncWithResult (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options = InvokeOptions.None) {
+ var tcs = new TaskCompletionSource<InvokeResult> ();
+ BeginInvokeMethod (thread, method, arguments, options, iar =>
+ {
+ try {
+ tcs.SetResult (EndInvokeMethodInternalWithResult (iar));
+ } catch (OperationCanceledException) {
+ tcs.TrySetCanceled ();
+ } catch (Exception ex) {
+ tcs.TrySetException (ex);
+ }
+ }, null);
+ return tcs.Task;
+ }
#endif
//
get; set;
}
+ public ValueImpl[] OutArgs {
+ get; set;
+ }
+
public ValueImpl Exception {
get; set;
}
f |= InvokeFlags.SINGLE_THREADED;
if ((options & InvokeOptions.ReturnOutThis) != 0)
f |= InvokeFlags.OUT_THIS;
+ if ((options & InvokeOptions.ReturnOutArgs) != 0)
+ f |= InvokeFlags.OUT_ARGS;
InvokeAsyncResult r = new InvokeAsyncResult { AsyncState = state, AsyncWaitHandle = new ManualResetEvent (false), VM = vm, Thread = thread, Callback = callback };
thread.InvalidateFrames ();
}
// This is called when the result of an invoke is received
- static void InvokeCB (ValueImpl v, ValueImpl exc, ValueImpl out_this, ErrorCode error, object state) {
+ static void InvokeCB (ValueImpl v, ValueImpl exc, ValueImpl out_this, ValueImpl[] out_args, ErrorCode error, object state) {
InvokeAsyncResult r = (InvokeAsyncResult)state;
if (error != 0) {
}
r.OutThis = out_this;
+ r.OutArgs = out_args;
r.IsCompleted = true;
((ManualResetEvent)r.AsyncWaitHandle).Set ();
if (r.Exception != null)
throw new InvocationException ((ObjectMirror)r.VM.DecodeValue (r.Exception));
- return new InvokeResult () { Result = r.VM.DecodeValue (r.Value), OutThis = r.OutThis != null ? r.VM.DecodeValue (r.OutThis) : null };
+ Value out_this = null;
+ if (r.OutThis != null)
+ out_this = r.VM.DecodeValue (r.OutThis);
+ Value[] out_args = null;
+ if (r.OutArgs != null)
+ out_args = r.VM.DecodeValues (r.OutArgs);
+
+ return new InvokeResult () { Result = r.VM.DecodeValue (r.Value), OutThis = out_this, OutArgs = out_args };
}
}
}
// This is called when the result of an invoke is received
- static void InvokeMultipleCB (ValueImpl v, ValueImpl exc, ValueImpl out_this, ErrorCode error, object state) {
+ static void InvokeMultipleCB (ValueImpl v, ValueImpl exc, ValueImpl out_this, ValueImpl[] out_args, ErrorCode error, object state) {
var r = (InvokeAsyncResult)state;
Interlocked.Decrement (ref r.NumPending);
return 42;
}
+ public void invoke_out (out int foo) {
+ foo = 5;
+ }
+
[MethodImplAttribute (MethodImplOptions.NoInlining)]
public static void exceptions () {
try {
Assert.AreEqual ("Exception", ex.Exception.Type.Name);
}
+#if NET_4_5
+ // out argument
+ m = t.GetMethod ("invoke_out");
+ var out_task = this_obj.InvokeMethodAsyncWithResult (e.Thread, m, new Value [] { vm.CreateValue (1) }, InvokeOptions.ReturnOutArgs);
+ var out_args = out_task.Result.OutArgs;
+ AssertValue (5, out_args [0]);
+
+ // without ReturnOutArgs flag
+ out_task = this_obj.InvokeMethodAsyncWithResult (e.Thread, m, new Value [] { vm.CreateValue (1) });
+ out_args = out_task.Result.OutArgs;
+ Assert.IsNull (out_args);
+#endif
+
// newobj
m = t.GetMethod (".ctor");
v = t.InvokeMethod (e.Thread, m, null);
#define HEADER_LENGTH 11
#define MAJOR_VERSION 2
-#define MINOR_VERSION 35
+#define MINOR_VERSION 36
typedef enum {
CMD_SET_VM = 1,
typedef enum {
INVOKE_FLAG_DISABLE_BREAKPOINTS = 1,
INVOKE_FLAG_SINGLE_THREADED = 2,
- INVOKE_FLAG_RETURN_OUT_THIS = 4
+ INVOKE_FLAG_RETURN_OUT_THIS = 4,
+ INVOKE_FLAG_RETURN_OUT_ARGS = 8
} InvokeFlags;
typedef enum {
buffer_add_byte (buf, 0);
buffer_add_value (buf, &mono_defaults.object_class->byval_arg, &exc, domain);
} else {
+ gboolean out_this = FALSE;
+ gboolean out_args = FALSE;
+
if ((invoke->flags & INVOKE_FLAG_RETURN_OUT_THIS) && CHECK_PROTOCOL_VERSION (2, 35))
- buffer_add_byte (buf, 2);
- else
- buffer_add_byte (buf, 1);
+ out_this = TRUE;
+ if ((invoke->flags & INVOKE_FLAG_RETURN_OUT_ARGS) && CHECK_PROTOCOL_VERSION (2, 35))
+ out_args = TRUE;
+ buffer_add_byte (buf, 1 + (out_this ? 2 : 0) + (out_args ? 4 : 0));
if (sig->ret->type == MONO_TYPE_VOID) {
if (!strcmp (m->name, ".ctor") && !m->klass->valuetype) {
buffer_add_value (buf, &mono_defaults.object_class->byval_arg, &this, domain);
} else {
NOT_IMPLEMENTED;
}
- if ((invoke->flags & INVOKE_FLAG_RETURN_OUT_THIS) && CHECK_PROTOCOL_VERSION (2, 35))
+ if (out_this)
/* Return the new value of the receiver after the call */
buffer_add_value (buf, &m->klass->byval_arg, this_buf, domain);
+ if (out_args) {
+ buffer_add_int (buf, nargs);
+ for (i = 0; i < nargs; ++i) {
+ if (MONO_TYPE_IS_REFERENCE (sig->params [i]))
+ buffer_add_value (buf, sig->params [i], &args [i], domain);
+ else if (sig->params [i]->byref)
+ /* add_value () does an indirection */
+ buffer_add_value (buf, sig->params [i], &arg_buf [i], domain);
+ else
+ buffer_add_value (buf, sig->params [i], arg_buf [i], domain);
+ }
+ }
}
tls->disable_breakpoints = FALSE;