Imported Upstream version 3.8.0

Former-commit-id: 6a76a29bd07d86e57c6c8da45c65ed5447d38a61
This commit is contained in:
Jo Shields
2014-09-04 09:07:35 +01:00
parent a575963da9
commit fe777c5c82
1062 changed files with 12460 additions and 5983 deletions

View File

@@ -8,6 +8,11 @@ LIB_MCS_FLAGS = /r:$(corlib) /r:System.dll /r:Mono.Cecil.dll /r:System.Core.dll
TEST_MCS_FLAGS = /r:Mono.Cecil.dll /r:System.dll /r:System.Core.dll
VALID_TEST_PROFILE := $(filter net_4_5, $(PROFILE))
# The test exe is not profile specific, and compiling a 2.0 will make the 4.5 tests fail
ifdef VALID_TEST_PROFILE
test-local: dtest-app.exe dtest-excfilter.exe
dtest-app.exe: Test/dtest-app.cs
@@ -16,6 +21,13 @@ dtest-app.exe: Test/dtest-app.cs
dtest-excfilter.exe: Test/dtest-excfilter.il
MONO_PATH=$(topdir)/class/lib/$(PROFILE) $(INTERNAL_ILASM) -out:$@ /exe /debug Test/dtest-excfilter.il
else
NO_TEST=1
check:
endif
CLEAN_FILES = dtest-app.exe dtest-app.exe.mdb dtest-excfilter.exe dtest-excfilter.exe.mdb
EXTRA_DISTFILES = \

View File

@@ -157,7 +157,9 @@ namespace Mono.Debugger.Soft
enum InvokeFlags {
NONE = 0x0,
DISABLE_BREAKPOINTS = 0x1,
SINGLE_THREADED = 0x2
SINGLE_THREADED = 0x2,
OUT_THIS = 0x4,
OUT_ARGS = 0x8,
}
enum ElementType {
@@ -404,8 +406,7 @@ namespace Mono.Debugger.Soft
static readonly bool EnableConnectionLogging = !String.IsNullOrEmpty (Environment.GetEnvironmentVariable ("MONO_SDB_LOG"));
static int ConnectionId;
readonly StreamWriter LoggingStream = EnableConnectionLogging ?
new StreamWriter (string.Format ("/tmp/sdb_conn_log_{0}", ConnectionId++), false) : null;
readonly StreamWriter LoggingStream;
/*
* Th version of the wire-protocol implemented by the library. The library
@@ -415,7 +416,7 @@ namespace Mono.Debugger.Soft
* with newer runtimes, and vice versa.
*/
internal const int MAJOR_VERSION = 2;
internal const int MINOR_VERSION = 34;
internal const int MINOR_VERSION = 35;
enum WPSuspendPolicy {
NONE = 0,
@@ -1068,6 +1069,19 @@ namespace Mono.Debugger.Soft
reply_cbs = new Dictionary<int, ReplyCallback> ();
reply_cb_counts = new Dictionary<int, int> ();
reply_packets_monitor = new Object ();
if (EnableConnectionLogging) {
var path = Environment.GetEnvironmentVariable ("MONO_SDB_LOG");
if (path.Contains ("{0}")) {
//C:\SomeDir\sdbLog{0}.txt -> C:\SomeDir\sdbLog1.txt
LoggingStream = new StreamWriter (string.Format (path, ConnectionId++), false);
} else if (Path.HasExtension (path)) {
//C:\SomeDir\sdbLog.txt -> C:\SomeDir\sdbLog1.txt
LoggingStream = new StreamWriter (Path.GetDirectoryName (path) + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension (path) + ConnectionId++ + "." + Path.GetExtension (path), false);
} else {
//C:\SomeDir\sdbLog -> C:\SomeDir\sdbLog1
LoggingStream = new StreamWriter (path + ConnectionId++, false);
}
}
}
protected abstract int TransportReceive (byte[] buf, int buf_offset, int len);
@@ -1432,18 +1446,18 @@ namespace Mono.Debugger.Soft
//
public void StartBuffering () {
buffer_packets = true;
if (Version.AtLeast (3, 34))
if (Version.AtLeast (2, 34))
VM_StartBuffering ();
}
public void StopBuffering () {
if (Version.AtLeast (3, 34))
if (Version.AtLeast (2, 34))
VM_StopBuffering ();
buffer_packets = false;
WritePackets (buffered_packets);
if (EnableConnectionLogging) {
LoggingStream.WriteLine (String.Format ("Sent {1} packets.", buffered_packets.Count));
LoggingStream.WriteLine (String.Format ("Sent {0} packets.", buffered_packets.Count));
LoggingStream.Flush ();
}
buffered_packets.Clear ();
@@ -1655,24 +1669,39 @@ namespace Mono.Debugger.Soft
}
}
internal delegate void InvokeMethodCallback (ValueImpl v, ValueImpl exc, 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;
ValueImpl v, exc, out_this = null;
ValueImpl[] out_args = null;
if (r.ErrorCode != 0) {
callback (null, null, (ErrorCode)r.ErrorCode, state);
callback (null, null, null, null, (ErrorCode)r.ErrorCode, state);
} else {
if (r.ReadByte () == 0) {
exc = r.ReadValue ();
v = null;
} else {
v = r.ReadValue ();
exc = null;
}
callback (v, exc, 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);
}
@@ -1690,20 +1719,14 @@ namespace Mono.Debugger.Soft
w.WriteValues (arguments [i]);
}
return Send (CommandSet.VM, (int)CmdVM.INVOKE_METHODS, w, delegate (PacketReader r) {
ValueImpl v, exc;
ValueImpl v, exc, out_this = null;
ValueImpl[] out_args = null;
if (r.ErrorCode != 0) {
callback (null, null, (ErrorCode)r.ErrorCode, state);
callback (null, null, null, null, (ErrorCode)r.ErrorCode, state);
} else {
if (r.ReadByte () == 0) {
exc = r.ReadValue ();
v = null;
} else {
v = r.ReadValue ();
exc = null;
}
callback (v, exc, 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);
}
@@ -1983,21 +2006,20 @@ namespace Mono.Debugger.Soft
return SendReceive (CommandSet.THREAD, (int)CmdThread.GET_NAME, new PacketWriter ().WriteId (id)).ReadString ();
}
internal FrameInfo[] Thread_GetFrameInfo (long id, int start_frame, int length) {
var res = SendReceive (CommandSet.THREAD, (int)CmdThread.GET_FRAME_INFO, new PacketWriter ().WriteId (id).WriteInt (start_frame).WriteInt (length));
int count = res.ReadInt ();
var frames = new FrameInfo [count];
for (int i = 0; i < count; ++i) {
var f = new FrameInfo ();
f.id = res.ReadInt ();
f.method = res.ReadId ();
f.il_offset = res.ReadInt ();
f.flags = (StackFrameFlags)res.ReadByte ();
frames [i] = f;
}
return frames;
internal void Thread_GetFrameInfo (long id, int start_frame, int length, Action<FrameInfo[]> resultCallaback) {
Send (CommandSet.THREAD, (int)CmdThread.GET_FRAME_INFO, new PacketWriter ().WriteId (id).WriteInt (start_frame).WriteInt (length), (res) => {
int count = res.ReadInt ();
var frames = new FrameInfo[count];
for (int i = 0; i < count; ++i) {
var f = new FrameInfo ();
f.id = res.ReadInt ();
f.method = res.ReadId ();
f.il_offset = res.ReadInt ();
f.flags = (StackFrameFlags)res.ReadByte ();
frames [i] = f;
}
resultCallaback (frames);
}, 1);
}
internal int Thread_GetState (long id) {

View File

@@ -23,67 +23,347 @@ namespace Mono.Debugger.Soft
// IL_0008: br IL_000d
// IL_000d: ldloc.0
// IL_000e: ret
// ... or returns a simple constant:
// IL_0000: ldc.i4 1024
// IL_0005: conv.i8
// IL_0006: ret
if (args != null && args.Length != 0)
throw new NotSupportedException ();
throw new NotSupportedException ();
if (method.IsStatic || method.DeclaringType.IsValueType || this_val == null || !(this_val is ObjectMirror))
throw new NotSupportedException ();
var instructions = body.Instructions;
if (instructions.Count > 16)
if (instructions.Count < 1 || instructions.Count > 16)
throw new NotSupportedException ();
Value[] stack = new Value [16];
Value locals_0 = null;
Value res = null;
int sp = 0;
int ins_count = 0;
var stack = new Value [16];
var ins = instructions [0];
Value locals_0 = null;
int ins_count = 0;
int sp = 0;
while (ins != null) {
if (ins_count > 16)
throw new NotImplementedException ();
ins_count ++;
var next = ins.Next;
ins_count++;
var op = ins.OpCode;
if (op == OpCodes.Nop) {
} else if (op == OpCodes.Ldarg_0) {
if (sp > 0)
if (sp != 0)
throw new NotSupportedException ();
stack [sp++] = this_val;
} else if (op == OpCodes.Ldfld) {
if (sp != 1)
throw new NotSupportedException ();
var obj = (ObjectMirror)stack [--sp];
var field = (FieldInfoMirror)ins.Operand;
var obj = (ObjectMirror) stack [--sp];
var field = (FieldInfoMirror) ins.Operand;
try {
stack [sp++] = obj.GetValue (field);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Ldc_I4_0) {
if (sp != 0)
throw new NotSupportedException ();
try {
stack [sp++] = new PrimitiveValue (method.VirtualMachine, 0);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Ldc_I4_1) {
if (sp != 0)
throw new NotSupportedException ();
try {
stack [sp++] = new PrimitiveValue (method.VirtualMachine, 1);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Ldc_I4_2) {
if (sp != 0)
throw new NotSupportedException ();
try {
stack [sp++] = new PrimitiveValue (method.VirtualMachine, 2);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Ldc_I4_3) {
if (sp != 0)
throw new NotSupportedException ();
try {
stack [sp++] = new PrimitiveValue (method.VirtualMachine, 3);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Ldc_I4_4) {
if (sp != 0)
throw new NotSupportedException ();
try {
stack [sp++] = new PrimitiveValue (method.VirtualMachine, 4);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Ldc_I4_5) {
if (sp != 0)
throw new NotSupportedException ();
try {
stack [sp++] = new PrimitiveValue (method.VirtualMachine, 5);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Ldc_I4_6) {
if (sp != 0)
throw new NotSupportedException ();
try {
stack [sp++] = new PrimitiveValue (method.VirtualMachine, 6);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Ldc_I4_7) {
if (sp != 0)
throw new NotSupportedException ();
try {
stack [sp++] = new PrimitiveValue (method.VirtualMachine, 7);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Ldc_I4_8) {
if (sp != 0)
throw new NotSupportedException ();
try {
stack [sp++] = new PrimitiveValue (method.VirtualMachine, 8);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Ldc_I4_M1) {
if (sp != 0)
throw new NotSupportedException ();
try {
stack [sp++] = new PrimitiveValue (method.VirtualMachine, -1);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Ldc_I4) {
if (sp != 0)
throw new NotSupportedException ();
try {
stack [sp++] = new PrimitiveValue (method.VirtualMachine, ins.Operand);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Ldc_I4_S) {
if (sp != 0)
throw new NotSupportedException ();
try {
stack [sp++] = new PrimitiveValue (method.VirtualMachine, ins.Operand);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Ldc_I8) {
if (sp != 0)
throw new NotSupportedException ();
try {
stack [sp++] = new PrimitiveValue (method.VirtualMachine, ins.Operand);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Ldc_R4) {
if (sp != 0)
throw new NotSupportedException ();
try {
stack [sp++] = new PrimitiveValue (method.VirtualMachine, ins.Operand);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Ldc_R8) {
if (sp != 0)
throw new NotSupportedException ();
try {
stack [sp++] = new PrimitiveValue (method.VirtualMachine, ins.Operand);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Conv_I) {
if (sp != 1)
throw new NotSupportedException ();
try {
var primitive = (PrimitiveValue) stack [--sp];
stack [sp++] = new PrimitiveValue (method.VirtualMachine, Convert.ToInt32 (primitive.Value));
} catch {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Conv_I1) {
if (sp != 1)
throw new NotSupportedException ();
try {
var primitive = (PrimitiveValue) stack [--sp];
stack [sp++] = new PrimitiveValue (method.VirtualMachine, Convert.ToSByte (primitive.Value));
} catch {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Conv_U1) {
if (sp != 1)
throw new NotSupportedException ();
try {
var primitive = (PrimitiveValue) stack [--sp];
stack [sp++] = new PrimitiveValue (method.VirtualMachine, Convert.ToByte (primitive.Value));
} catch {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Conv_I2) {
if (sp != 1)
throw new NotSupportedException ();
try {
var primitive = (PrimitiveValue) stack [--sp];
stack [sp++] = new PrimitiveValue (method.VirtualMachine, Convert.ToInt16 (primitive.Value));
} catch {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Conv_U2) {
if (sp != 1)
throw new NotSupportedException ();
try {
var primitive = (PrimitiveValue) stack [--sp];
stack [sp++] = new PrimitiveValue (method.VirtualMachine, Convert.ToUInt16 (primitive.Value));
} catch {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Conv_I4) {
if (sp != 1)
throw new NotSupportedException ();
try {
var primitive = (PrimitiveValue) stack [--sp];
stack [sp++] = new PrimitiveValue (method.VirtualMachine, Convert.ToInt32 (primitive.Value));
} catch {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Conv_U4) {
if (sp != 1)
throw new NotSupportedException ();
try {
var primitive = (PrimitiveValue) stack [--sp];
stack [sp++] = new PrimitiveValue (method.VirtualMachine, Convert.ToUInt32 (primitive.Value));
} catch {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Conv_I8) {
if (sp != 1)
throw new NotSupportedException ();
try {
var primitive = (PrimitiveValue) stack [--sp];
stack [sp++] = new PrimitiveValue (method.VirtualMachine, Convert.ToInt64 (primitive.Value));
} catch {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Conv_U8) {
if (sp != 1)
throw new NotSupportedException ();
try {
var primitive = (PrimitiveValue) stack [--sp];
stack [sp++] = new PrimitiveValue (method.VirtualMachine, Convert.ToUInt64 (primitive.Value));
} catch {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Conv_R4) {
if (sp != 1)
throw new NotSupportedException ();
try {
var primitive = (PrimitiveValue) stack [--sp];
stack [sp++] = new PrimitiveValue (method.VirtualMachine, Convert.ToSingle (primitive.Value));
} catch {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Conv_R8) {
if (sp != 1)
throw new NotSupportedException ();
try {
var primitive = (PrimitiveValue) stack [--sp];
stack [sp++] = new PrimitiveValue (method.VirtualMachine, Convert.ToDouble (primitive.Value));
} catch {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Stloc_0) {
if (sp != 1)
throw new NotSupportedException ();
locals_0 = stack [--sp];
} else if (op == OpCodes.Br) {
next = (ILInstruction)ins.Operand;
next = (ILInstruction) ins.Operand;
} else if (op == OpCodes.Ldloc_0) {
if (sp != 0)
throw new NotSupportedException ();
stack [sp++] = locals_0;
} else if (op == OpCodes.Ret) {
if (sp == 0)
res = null;
else
res = stack [--sp];
break;
if (sp > 0) {
var res = stack [--sp];
var primitive = res as PrimitiveValue;
if (method.ReturnType.IsPrimitive && primitive != null) {
// cast the primitive value to the return type
try {
switch (method.ReturnType.CSharpName) {
case "double": res = new PrimitiveValue (method.VirtualMachine, Convert.ToDouble (primitive.Value)); break;
case "float": res = new PrimitiveValue (method.VirtualMachine, Convert.ToSingle (primitive.Value)); break;
case "ulong": res = new PrimitiveValue (method.VirtualMachine, Convert.ToUInt64 (primitive.Value)); break;
case "long": res = new PrimitiveValue (method.VirtualMachine, Convert.ToInt64 (primitive.Value)); break;
case "uint": res = new PrimitiveValue (method.VirtualMachine, Convert.ToUInt32 (primitive.Value)); break;
case "int": res = new PrimitiveValue (method.VirtualMachine, Convert.ToInt32 (primitive.Value)); break;
case "ushort": res = new PrimitiveValue (method.VirtualMachine, Convert.ToUInt16 (primitive.Value)); break;
case "short": res = new PrimitiveValue (method.VirtualMachine, Convert.ToInt16 (primitive.Value)); break;
case "sbyte": res = new PrimitiveValue (method.VirtualMachine, Convert.ToSByte (primitive.Value)); break;
case "byte": res = new PrimitiveValue (method.VirtualMachine, Convert.ToByte (primitive.Value)); break;
case "char": res = new PrimitiveValue (method.VirtualMachine, Convert.ToChar (primitive.Value)); break;
case "bool": res = new PrimitiveValue (method.VirtualMachine, Convert.ToBoolean (primitive.Value)); break;
}
} catch {
throw new NotSupportedException ();
}
}
return res;
}
return null;
} else {
throw new NotSupportedException ();
}
ins = next;
}
return res;
return null;
}
}
}

View File

@@ -13,6 +13,15 @@ namespace Mono.Debugger.Soft
/*
* Only resume the target thread during the invoke
*/
SingleThreaded = 2
SingleThreaded = 2,
/*
* Return the changed receiver when invoking
* a valuetype method.
*/
ReturnOutThis = 4,
/*
* Return the values of out arguments
*/
ReturnOutArgs = 8
}
}

View File

@@ -8,6 +8,22 @@ using System.Threading.Tasks;
namespace Mono.Debugger.Soft
{
public class InvokeResult {
public Value Result { get; set; }
//
// The value of the receiver after the call for calls to valuetype methods or null.
// Only set when using the InvokeOptions.ReturnOutThis flag.
// 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 {
TypeMirror type;
AppDomainMirror domain;
@@ -149,6 +165,10 @@ namespace Mono.Debugger.Soft
return EndInvokeMethodInternal (asyncResult);
}
public InvokeResult EndInvokeMethodWithResult (IAsyncResult asyncResult) {
return ObjectMirror.EndInvokeMethodInternalWithResult (asyncResult);
}
#if NET_4_5
public Task<Value> InvokeMethodAsync (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options = InvokeOptions.None) {
var tcs = new TaskCompletionSource<Value> ();
@@ -164,6 +184,21 @@ namespace Mono.Debugger.Soft
}, 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
//
@@ -223,6 +258,14 @@ namespace Mono.Debugger.Soft
get; set;
}
public ValueImpl OutThis {
get; set;
}
public ValueImpl[] OutArgs {
get; set;
}
public ValueImpl Exception {
get; set;
}
@@ -260,16 +303,20 @@ namespace Mono.Debugger.Soft
f |= InvokeFlags.DISABLE_BREAKPOINTS;
if ((options & InvokeOptions.SingleThreaded) != 0)
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 ();
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);
return r;
}
// This is called when the result of an invoke is received
static void InvokeCB (ValueImpl v, ValueImpl exc, 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) {
@@ -279,6 +326,9 @@ namespace Mono.Debugger.Soft
r.Exception = exc;
}
r.OutThis = out_this;
r.OutArgs = out_args;
r.IsCompleted = true;
((ManualResetEvent)r.AsyncWaitHandle).Set ();
@@ -286,7 +336,7 @@ namespace Mono.Debugger.Soft
r.Callback.BeginInvoke (r, null, null);
}
internal static Value EndInvokeMethodInternal (IAsyncResult asyncResult) {
internal static InvokeResult EndInvokeMethodInternalWithResult (IAsyncResult asyncResult) {
if (asyncResult == null)
throw new ArgumentNullException ("asyncResult");
@@ -301,18 +351,30 @@ namespace Mono.Debugger.Soft
} catch (CommandException ex) {
if (ex.ErrorCode == ErrorCode.INVALID_ARGUMENT)
throw new ArgumentException ("Incorrect number or types of arguments", "arguments");
else
throw;
throw;
}
throw new NotImplementedException ();
} else {
if (r.Exception != null)
throw new InvocationException ((ObjectMirror)r.VM.DecodeValue (r.Exception));
else
return r.VM.DecodeValue (r.Value);
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 };
}
}
internal static Value EndInvokeMethodInternal (IAsyncResult asyncResult) {
InvokeResult res = EndInvokeMethodInternalWithResult (asyncResult);
return res.Result;
}
internal static void EndInvokeMultipleInternal (IAsyncResult asyncResult) {
if (asyncResult == null)
throw new ArgumentNullException ("asyncResult");
@@ -370,13 +432,14 @@ namespace Mono.Debugger.Soft
var args = new List<ValueImpl[]> ();
for (int i = 0; i < methods.Length; ++i)
args.Add (vm.EncodeValues (arguments [i]));
thread.InvalidateFrames ();
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);
return r;
}
// This is called when the result of an invoke is received
static void InvokeMultipleCB (ValueImpl v, ValueImpl exc, 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);

View File

@@ -22,8 +22,11 @@ namespace Mono.Debugger.Soft
public override bool Equals (object obj) {
if (value == obj)
return true;
if (obj != null && obj is PrimitiveValue)
return value == (obj as PrimitiveValue).Value;
var primitive = obj as PrimitiveValue;
if (primitive != null)
return value == primitive.Value;
return base.Equals (obj);
}
@@ -52,5 +55,9 @@ namespace Mono.Debugger.Soft
public Value EndInvokeMethod (IAsyncResult asyncResult) {
return ObjectMirror.EndInvokeMethodInternal (asyncResult);
}
public InvokeResult EndInvokeMethodWithResult (IAsyncResult asyncResult) {
return ObjectMirror.EndInvokeMethodInternalWithResult (asyncResult);
}
}
}

View File

@@ -1,5 +1,8 @@
using System;
using System.Collections.Generic;
#if NET_4_5
using System.Threading.Tasks;
#endif
namespace Mono.Debugger.Soft
{
@@ -83,7 +86,53 @@ namespace Mono.Debugger.Soft
}
public Value EndInvokeMethod (IAsyncResult asyncResult) {
return ObjectMirror.EndInvokeMethodInternal (asyncResult);
var result = ObjectMirror.EndInvokeMethodInternalWithResult (asyncResult);
var outThis = result.OutThis as StructMirror;
if (outThis != null) {
SetFields (outThis.Fields);
}
return result.Result;
}
public InvokeResult EndInvokeMethodWithResult (IAsyncResult asyncResult) {
var result = ObjectMirror.EndInvokeMethodInternalWithResult (asyncResult);
var outThis = result.OutThis as StructMirror;
if (outThis != null) {
SetFields (outThis.Fields);
}
return result;
}
#if NET_4_5
public Task<Value> InvokeMethodAsync (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options = InvokeOptions.None) {
var tcs = new TaskCompletionSource<Value> ();
BeginInvokeMethod (thread, method, arguments, options, iar =>
{
try {
tcs.SetResult (EndInvokeMethod (iar));
} catch (OperationCanceledException) {
tcs.TrySetCanceled ();
} catch (Exception ex) {
tcs.TrySetException (ex);
}
}, 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 (ObjectMirror.EndInvokeMethodInternalWithResult (iar));
} catch (OperationCanceledException) {
tcs.TrySetCanceled ();
} catch (Exception ex) {
tcs.TrySetException (ex);
}
}, null);
return tcs.Task;
}
#endif
}
}

View File

@@ -7,7 +7,12 @@ namespace Mono.Debugger.Soft
public class ThreadMirror : ObjectMirror
{
string name;
bool cacheInvalid = true;
bool fetching;
object fetchingLocker = new object ();
ManualResetEvent fetchingEvent = new ManualResetEvent (false);
ThreadInfo info;
StackFrame[] frames;
internal ThreadMirror (VirtualMachine vm, long id) : base (vm, id) {
}
@@ -15,22 +20,58 @@ namespace Mono.Debugger.Soft
internal ThreadMirror (VirtualMachine vm, long id, TypeMirror type, AppDomainMirror domain) : base (vm, id, type, domain) {
}
// FIXME: Cache, invalidate when the thread/runtime is resumed
public StackFrame[] GetFrames () {
FrameInfo[] frame_info = vm.conn.Thread_GetFrameInfo (id, 0, -1);
FetchFrames (true);
fetchingEvent.WaitOne ();
return frames;
}
var frames = new List<StackFrame> ();
internal void InvalidateFrames () {
cacheInvalid = true;
}
for (int i = 0; i < frame_info.Length; ++i) {
FrameInfo info = (FrameInfo)frame_info [i];
MethodMirror method = vm.GetMethod (info.method);
var f = new StackFrame (vm, info.id, this, method, info.il_offset, info.flags);
if (!(f.IsNativeTransition && !NativeTransitions))
frames.Add (f);
internal void FetchFrames (bool mustFetch = false) {
lock (fetchingLocker) {
if (fetching || !cacheInvalid)
return;
cacheInvalid = false;
fetching = true;
fetchingEvent.Reset ();
}
vm.conn.Thread_GetFrameInfo (id, 0, -1, (frame_info) => {
var framesList = new List<StackFrame> ();
for (int i = 0; i < frame_info.Length; ++i) {
var frameInfo = (FrameInfo)frame_info [i];
var method = vm.GetMethod (frameInfo.method);
var f = new StackFrame (vm, frameInfo.id, this, method, frameInfo.il_offset, frameInfo.flags);
if (!(f.IsNativeTransition && !NativeTransitions))
framesList.Add (f);
}
lock (fetchingLocker) {
vm.AddThreadToInvalidateList (this);
fetching = false;
//In case it was invalidated during waiting for response from
//runtime and mustFetch was set refetch
if (cacheInvalid && mustFetch) {
FetchFrames (mustFetch);
return;
}
frames = framesList.ToArray ();
fetchingEvent.Set ();
}
});
}
return frames.ToArray ();
}
public static void FetchFrames(IList<ThreadMirror> threads)
{
if (threads.Count == 0)
return;
threads [0].vm.conn.StartBuffering ();
foreach (var thread in threads) {
thread.FetchFrames ();
}
threads [0].vm.conn.StopBuffering ();
}
public string Name {
get {
@@ -38,7 +79,7 @@ namespace Mono.Debugger.Soft
name = vm.conn.Thread_GetName (id);
return name;
}
}
}
public new long Id {
get {
@@ -111,8 +152,8 @@ namespace Mono.Debugger.Soft
} catch (CommandException ex) {
if (ex.ErrorCode == ErrorCode.INVALID_ARGUMENT)
throw new ArgumentException ("loc doesn't refer to a location in the current method of this thread.", "loc");
else
throw;
throw;
}
}
}

View File

@@ -806,6 +806,10 @@ namespace Mono.Debugger.Soft
return ObjectMirror.EndInvokeMethodInternal (asyncResult);
}
public InvokeResult EndInvokeMethodWithResult (IAsyncResult asyncResult) {
return ObjectMirror.EndInvokeMethodInternalWithResult (asyncResult);
}
#if NET_4_5
public Task<Value> InvokeMethodAsync (ThreadMirror thread, MethodMirror method, IList<Value> arguments, InvokeOptions options = InvokeOptions.None) {
var tcs = new TaskCompletionSource<Value> ();

View File

@@ -121,12 +121,13 @@ namespace Mono.Debugger.Soft
public void Resume () {
try {
InvalidateThreadAndFrameCaches ();
conn.VM_Resume ();
} catch (CommandException ex) {
if (ex.ErrorCode == ErrorCode.NOT_SUSPENDED)
throw new VMNotSuspendedException ();
else
throw;
throw;
}
}
@@ -151,12 +152,44 @@ namespace Mono.Debugger.Soft
conn.ForceDisconnect ();
}
HashSet<ThreadMirror> threadsToInvalidate = new HashSet<ThreadMirror> ();
ThreadMirror[] threadCache;
object threadCacheLocker = new object ();
void InvalidateThreadAndFrameCaches () {
lock (threadsToInvalidate) {
foreach (var thread in threadsToInvalidate)
thread.InvalidateFrames ();
threadsToInvalidate.Clear ();
}
lock (threadCacheLocker) {
threadCache = null;
}
}
internal void InvalidateThreadCache () {
lock (threadCacheLocker) {
threadCache = null;
}
}
internal void AddThreadToInvalidateList (ThreadMirror threadMirror)
{
lock (threadsToInvalidate) {
threadsToInvalidate.Add (threadMirror);
}
}
public IList<ThreadMirror> GetThreads () {
long[] ids = vm.conn.VM_GetThreads ();
ThreadMirror[] res = new ThreadMirror [ids.Length];
for (int i = 0; i < ids.Length; ++i)
res [i] = GetThread (ids [i]);
return res;
lock (threadCacheLocker) {
if (threadCache == null) {
long[] ids = vm.conn.VM_GetThreads ();
threadCache = new ThreadMirror [ids.Length];
for (int i = 0; i < ids.Length; ++i)
threadCache [i] = GetThread (ids [i]);
}
return threadCache;
}
}
// Same as the mirrorOf methods in JDI
@@ -675,9 +708,11 @@ namespace Mono.Debugger.Soft
vm.notify_vm_event (EventType.VMDeath, suspend_policy, req_id, thread_id, null, ei.ExitCode);
break;
case EventType.ThreadStart:
vm.InvalidateThreadCache ();
l.Add (new ThreadStartEvent (vm, req_id, id));
break;
case EventType.ThreadDeath:
vm.InvalidateThreadCache ();
l.Add (new ThreadDeathEvent (vm, req_id, id));
break;
case EventType.AssemblyLoad:
@@ -718,8 +753,6 @@ namespace Mono.Debugger.Soft
case EventType.UserLog:
l.Add (new UserLogEvent (vm, req_id, thread_id, ei.Level, ei.Category, ei.Message));
break;
default:
break;
}
}

View File

@@ -81,6 +81,7 @@ public struct AStruct {
public string s;
public byte k;
public IntPtr j;
public int l;
[MethodImplAttribute (MethodImplOptions.NoInlining)]
public int foo (int val) {
@@ -106,6 +107,11 @@ public struct AStruct {
public IntPtr invoke_return_intptr () {
return j;
}
[MethodImplAttribute (MethodImplOptions.NoInlining)]
public void invoke_mutate () {
l = 5;
}
}
public class GClass<T> {
@@ -953,6 +959,11 @@ public class Tests : TestsBase, ITest2
return 42;
}
public void invoke_out (out int foo, out int[] arr) {
foo = 5;
arr = new int [10];
}
[MethodImplAttribute (MethodImplOptions.NoInlining)]
public static void exceptions () {
try {

View File

@@ -2110,6 +2110,21 @@ public class DebuggerTests
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), vm.CreateValue (null) }, InvokeOptions.ReturnOutArgs);
var out_args = out_task.Result.OutArgs;
AssertValue (5, out_args [0]);
Assert.IsTrue (out_args [1] is ArrayMirror);
Assert.AreEqual (10, (out_args [1] as ArrayMirror).Length);
// without ReturnOutArgs flag
out_task = this_obj.InvokeMethodAsyncWithResult (e.Thread, m, new Value [] { vm.CreateValue (1), vm.CreateValue (null) });
out_args = out_task.Result.OutArgs;
Assert.IsNull (out_args);
#endif
// newobj
m = t.GetMethod (".ctor");
v = t.InvokeMethod (e.Thread, m, null);
@@ -2212,6 +2227,24 @@ public class DebuggerTests
m = t.GetMethod ("invoke_return_int");
v = s.InvokeMethod (e.Thread, m, null);
AssertValue (42, v);
#if NET_4_5
// Invoke a method which changes state
s = frame.GetArgument (1) as StructMirror;
t = s.Type;
m = t.GetMethod ("invoke_mutate");
var task = s.InvokeMethodAsyncWithResult (e.Thread, m, null, InvokeOptions.ReturnOutThis);
var out_this = task.Result.OutThis as StructMirror;
AssertValue (5, out_this ["l"]);
// Without the ReturnOutThis flag
s = frame.GetArgument (1) as StructMirror;
t = s.Type;
m = t.GetMethod ("invoke_mutate");
task = s.InvokeMethodAsyncWithResult (e.Thread, m, null);
out_this = task.Result.OutThis as StructMirror;
Assert.AreEqual (null, out_this);
#endif
}
[Test]