Browse Source

Re-implemented fast property evaluation

newNRvisualizers
David Srbecký 13 years ago
parent
commit
86b779a8f0
  1. 15
      src/AddIns/Debugger/Debugger.Core/Eval.cs
  2. 66
      src/AddIns/Debugger/Debugger.Core/Module.cs
  3. 2
      src/AddIns/Debugger/Debugger.Core/StackFrame.cs
  4. 7
      src/AddIns/Debugger/Debugger.Core/TypeSystemExtensions.cs
  5. 57
      src/AddIns/Debugger/Debugger.Core/Value.cs

15
src/AddIns/Debugger/Debugger.Core/Eval.cs

@ -187,12 +187,15 @@ namespace Debugger @@ -187,12 +187,15 @@ namespace Debugger
/// <summary> Synchronously calls a function and returns its return value </summary>
public static Value InvokeMethod(Thread evalThread, IMethod method, Value thisValue, Value[] args)
{
#warning Fast property eval
// var field = Value.GetBackingField(method);
// if (field != null) {
// evalThread.Process.TraceMessage("Using backing field for " + method.FullName);
// return Value.GetMemberValue(evalThread, thisValue, field, args);
// }
Module module = method.DeclaringTypeDefinition.ParentAssembly.GetModule();
uint fieldToken = module.GetBackingFieldToken(method.ToCorFunction());
if (fieldToken != 0) {
var field = method.DeclaringType.ImportField(fieldToken);
if (field != null) {
evalThread.Process.TraceMessage("Using backing field for " + method.FullName);
return Value.GetMemberValue(evalThread, thisValue, field, args);
}
}
return AsyncInvokeMethod(evalThread, method, thisValue, args).WaitForResult();
}

66
src/AddIns/Debugger/Debugger.Core/Module.cs

@ -356,5 +356,71 @@ namespace Debugger @@ -356,5 +356,71 @@ namespace Debugger
}
return jcf;
}
Dictionary<ICorDebugFunction, uint> backingFieldCache = new Dictionary<ICorDebugFunction, uint>();
/// <summary> Is this method in form 'return this.field;'? </summary>
internal uint GetBackingFieldToken(ICorDebugFunction corFunction)
{
uint token;
if (backingFieldCache.TryGetValue(corFunction, out token)) {
return token;
}
ICorDebugCode corCode;
try {
corCode = corFunction.GetILCode();
} catch (COMException) {
backingFieldCache[corFunction] = 0;
return 0;
}
if (corCode == null || corCode.IsIL() == 0 || corCode.GetSize() > 12) {
backingFieldCache[corFunction] = 0;
return 0;
}
List<byte> code = new List<byte>(corCode.GetCode());
bool success =
(Read(code, 0x00) || true) && // nop || nothing
(Read(code, 0x02, 0x7B) || Read(code, 0x7E)) && // ldarg.0; ldfld || ldsfld
ReadToken(code, ref token) && // <field token>
(Read(code, 0x0A, 0x2B, 0x00, 0x06) || true) && // stloc.0; br.s; offset+00; ldloc.0 || nothing
Read(code, 0x2A); // ret
if (!success) {
backingFieldCache[corFunction] = 0;
return 0;
}
backingFieldCache[corFunction] = token;
return token;
}
// Read expected sequence of bytes
static bool Read(List<byte> code, params byte[] expected)
{
if (code.Count < expected.Length)
return false;
for(int i = 0; i < expected.Length; i++) {
if (code[i] != expected[i])
return false;
}
code.RemoveRange(0, expected.Length);
return true;
}
// Read field token
static bool ReadToken(List<byte> code, ref uint token)
{
if (code.Count < 4)
return false;
if (code[3] != 0x04) // field token
return false;
token = ((uint)code[0]) + ((uint)code[1] << 8) + ((uint)code[2] << 16) + ((uint)code[3] << 24);
code.RemoveRange(0, 4);
return true;
}
}
}

2
src/AddIns/Debugger/Debugger.Core/StackFrame.cs

@ -391,7 +391,7 @@ namespace Debugger @@ -391,7 +391,7 @@ namespace Debugger
if (this.MethodInfo.IsAccessor) return true;
}
if (opt.StepOverFieldAccessProperties) {
if (this.MethodInfo.IsAccessor && Value.GetBackingFieldToken(this.MethodInfo) != 0) return true;
if (this.MethodInfo.IsAccessor && this.Module.GetBackingFieldToken(this.CorFunction) != 0) return true;
}
return false;
}

7
src/AddIns/Debugger/Debugger.Core/TypeSystemExtensions.cs

@ -522,5 +522,12 @@ namespace Debugger @@ -522,5 +522,12 @@ namespace Debugger
}
return unresolvedMethod.Resolve(new SimpleTypeResolveContext(module.Assembly));
}
public static IField ImportField(this IType declaringType, uint fieldToken)
{
var module = declaringType.GetDefinition().ParentAssembly.GetModule();
var info = GetInfo(module.Assembly);
return declaringType.GetFields(f => info.GetMetadataToken(f) == fieldToken, GetMemberOptions.IgnoreInheritedMembers).SingleOrDefault();
}
}
}

57
src/AddIns/Debugger/Debugger.Core/Value.cs

@ -602,63 +602,6 @@ namespace Debugger @@ -602,63 +602,6 @@ namespace Debugger
#endregion
/// <summary> Is this method in form 'return this.field;'? </summary>
internal static uint GetBackingFieldToken(IMethod method)
{
ICorDebugFunction corFunction = method.ToCorFunction();
ICorDebugCode corCode;
try {
corCode = corFunction.GetILCode();
} catch (COMException) {
return 0;
}
if (corCode == null || corCode.IsIL() == 0 || corCode.GetSize() > 12)
return 0;
List<byte> code = new List<byte>(corCode.GetCode());
uint token = 0;
bool success =
(Read(code, 0x00) || true) && // nop || nothing
(Read(code, 0x02, 0x7B) || Read(code, 0x7E)) && // ldarg.0; ldfld || ldsfld
ReadToken(code, ref token) && // <field token>
(Read(code, 0x0A, 0x2B, 0x00, 0x06) || true) && // stloc.0; br.s; offset+00; ldloc.0 || nothing
Read(code, 0x2A); // ret
if (!success)
return 0;
return token;
}
// Read expected sequence of bytes
static bool Read(List<byte> code, params byte[] expected)
{
if (code.Count < expected.Length)
return false;
for(int i = 0; i < expected.Length; i++) {
if (code[i] != expected[i])
return false;
}
code.RemoveRange(0, expected.Length);
return true;
}
// Read field token
static bool ReadToken(List<byte> code, ref uint token)
{
if (code.Count < 4)
return false;
if (code[3] != 0x04) // field token
return false;
token = ((uint)code[0]) + ((uint)code[1] << 8) + ((uint)code[2] << 16) + ((uint)code[3] << 24);
code.RemoveRange(0, 4);
return true;
}
public override string ToString()
{
return this.AsString();

Loading…
Cancel
Save