From 4162f7ab31ad7d5d1e0a67b33662d673782ff9f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Thu, 20 Aug 2009 13:20:01 +0000 Subject: [PATCH] Expression caching git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4745 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Project/Debugger.Core.csproj | 1 + .../Src/Control/Process-StateControl.cs | 3 + .../Project/Src/Control/Process.cs | 9 +- .../Src/Expressions/ExpressionEvaluator.cs | 526 ++++++++++-------- .../Project/Src/Internal/ManagedCallback.cs | 8 +- .../Project/Src/Util/CallbackOnDispose.cs | 46 ++ 6 files changed, 369 insertions(+), 224 deletions(-) create mode 100644 src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Util/CallbackOnDispose.cs diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Debugger.Core.csproj b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Debugger.Core.csproj index a809c4ddd6..acf484f5c5 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Debugger.Core.csproj +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Debugger.Core.csproj @@ -266,6 +266,7 @@ + diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Process-StateControl.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Process-StateControl.cs index 165aea2a9a..215f3eea0f 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Process-StateControl.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Process-StateControl.cs @@ -5,6 +5,7 @@ // $Revision$ // +using ICSharpCode.NRefactory.Ast; using System; using System.Collections.Generic; @@ -16,6 +17,7 @@ namespace Debugger { internal bool TerminateCommandIssued = false; internal Queue BreakpointHitEventQueue = new Queue(); + internal Dictionary CachedExpressions = new Dictionary(); #region Events @@ -99,6 +101,7 @@ namespace Debugger if (action == DebuggeeStateAction.Clear) { if (debuggeeState == null) throw new DebuggerException("Debugee state already cleared"); debuggeeState = null; + this.CachedExpressions.Clear(); } } diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Process.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Process.cs index 501966b2f3..8f59f4376d 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Process.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Process.cs @@ -185,13 +185,16 @@ namespace Debugger } } - public void TraceMessage(string message, params object[] args) + public void TraceVerboseMessage(string message, params object[] args) { - TraceMessage(string.Format(message, args)); + if (this.Options.Verbose) + TraceMessage(message, args); } - public void TraceMessage(string message) + public void TraceMessage(string message, params object[] args) { + if (args.Length > 0) + message = string.Format(message, args); System.Diagnostics.Debug.WriteLine("Debugger:" + message); debugger.OnDebuggerTraceMessage(new MessageEventArgs(this, message)); } diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Expressions/ExpressionEvaluator.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Expressions/ExpressionEvaluator.cs index 5bc870a8bf..ffcf374728 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Expressions/ExpressionEvaluator.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Expressions/ExpressionEvaluator.cs @@ -8,6 +8,7 @@ using ICSharpCode.NRefactory.PrettyPrinter; using System; using System.Collections; using System.Collections.Generic; +using System.Diagnostics; using System.Text; using Debugger.MetaData; using ICSharpCode.NRefactory; @@ -18,7 +19,7 @@ namespace Debugger { public class ExpressionEvaluator: NotImplementedAstVisitor { - /// Evaluate given expression. If you expression tree already, use overloads of this method. + /// Evaluate given expression. If you have expression tree already, use overloads of this method. /// Returned value or null for statements public static Value Evaluate(string code, SupportedLanguage language, StackFrame context) { @@ -45,29 +46,12 @@ namespace Debugger } } - static Dictionary> expressionCache = new Dictionary>(); - public static Value Evaluate(INode code, StackFrame context) { if (context == null) throw new ArgumentNullException("context"); if (context.IsInvalid) throw new DebuggerException("The context is no longer valid"); - string codeAsText = code.PrettyPrint(); - - // Get value from cache if possible - if (expressionCache.ContainsKey(context.AppDomain) && - expressionCache[context.AppDomain].ContainsKey(codeAsText)) { - Value cached = expressionCache[context.AppDomain][codeAsText]; - if (!cached.IsInvalid) { - if (context.Process.Options.Verbose) { - context.Process.TraceMessage(string.Format("Cached: {0}", codeAsText)); - } - return cached; - } - } - Value result; - DateTime start = Debugger.Util.HighPrecisionTimer.Now; try { result = (Value)code.AcceptVisitor(new ExpressionEvaluator(context), null); } catch (GetValueException) { @@ -75,18 +59,6 @@ namespace Debugger } catch (NotImplementedException e) { throw new GetValueException(code, "Language feature not implemented: " + e.Message); } - DateTime end = Debugger.Util.HighPrecisionTimer.Now; - - // Store value in cache - if (!expressionCache.ContainsKey(context.AppDomain)) { - expressionCache[context.AppDomain] = new Dictionary(); - // TODO - } - // expressionCache[context.AppDomain][codeAsText] = result; - - if (context.Process.Options.Verbose) { - context.Process.TraceMessage(string.Format("Evaluated: {0} ({1} ms)", code, (end - start).TotalMilliseconds)); - } return result; } @@ -129,6 +101,34 @@ namespace Debugger } } + void AddToCache(INode expression, Value value) + { + // Expressions are cleared then the process is resumed + context.Process.CachedExpressions[expression] = value; + } + + bool TryGetCached(INode expression, out Value cached) + { + Value val; + if (context.Process.CachedExpressions.TryGetValue(expression, out val)) { + if (val == null || !val.IsInvalid) { + // context.Process.TraceMessage("Is cached: {0}", expression.PrettyPrint()); + cached = val; + return true; + } + } + cached = null; + return false; + } + + Value EvalAndPermRef(INode expression) + { + Value val = (Value)expression.AcceptVisitor(this, null); + if (val != null) + val = val.GetPermanentReference(); + AddToCache(expression, val); + return val; + } StackFrame context; @@ -141,256 +141,344 @@ namespace Debugger this.context = context; } - public override object VisitAssignmentExpression(AssignmentExpression assignmentExpression, object data) + IDisposable LogEval(INode expression) { - BinaryOperatorType op; - switch (assignmentExpression.Op) { - case AssignmentOperatorType.Assign: op = BinaryOperatorType.None; break; - case AssignmentOperatorType.Add: op = BinaryOperatorType.Add; break; - case AssignmentOperatorType.ConcatString: op = BinaryOperatorType.Concat; break; - case AssignmentOperatorType.Subtract: op = BinaryOperatorType.Subtract; break; - case AssignmentOperatorType.Multiply: op = BinaryOperatorType.Multiply; break; - case AssignmentOperatorType.Divide: op = BinaryOperatorType.Divide; break; - case AssignmentOperatorType.DivideInteger: op = BinaryOperatorType.DivideInteger; break; - case AssignmentOperatorType.ShiftLeft: op = BinaryOperatorType.ShiftLeft; break; - case AssignmentOperatorType.ShiftRight: op = BinaryOperatorType.ShiftRight; break; - case AssignmentOperatorType.ExclusiveOr: op = BinaryOperatorType.ExclusiveOr; break; - case AssignmentOperatorType.Modulus: op = BinaryOperatorType.Modulus; break; - case AssignmentOperatorType.BitwiseAnd: op = BinaryOperatorType.BitwiseAnd; break; - case AssignmentOperatorType.BitwiseOr: op = BinaryOperatorType.BitwiseOr; break; - case AssignmentOperatorType.Power: op = BinaryOperatorType.Power; break; - default: throw new GetValueException("Unknown operator " + assignmentExpression.Op); - } - - Value right; - if (op == BinaryOperatorType.None) { - right = (Value)assignmentExpression.Right.AcceptVisitor(this, null); - } else { - BinaryOperatorExpression binOpExpr = new BinaryOperatorExpression(); - binOpExpr.Left = assignmentExpression.Left; - binOpExpr.Op = op; - binOpExpr.Right = assignmentExpression.Right; - right = (Value)VisitBinaryOperatorExpression(binOpExpr, null); - } - right = right.GetPermanentReference(); - - Value left = ((Value)assignmentExpression.Left.AcceptVisitor(this, null)); - - if (!left.IsReference && left.Type.FullName != right.Type.FullName) { - throw new GetValueException(string.Format("Type {0} expected, {1} seen", left.Type.FullName, right.Type.FullName)); + Stopwatch watch = new Stopwatch(); + watch.Start(); + return new CallbackOnDispose(delegate { + if (!context.Process.CachedExpressions.ContainsKey(expression)) + throw new DebuggerException("Result not added to cache"); + watch.Stop(); + context.Process.TraceMessage("Evaluated: {0} in {1} ms total", expression.PrettyPrint(), watch.ElapsedMilliseconds); + }); + } + + public override object VisitEmptyStatement(EmptyStatement emptyStatement, object data) + { + using(LogEval(emptyStatement)) { + return null; } - left.SetValue(right); - return right; } - public override object VisitBlockStatement(BlockStatement blockStatement, object data) + public override object VisitExpressionStatement(ExpressionStatement expressionStatement, object data) { - foreach(INode statement in blockStatement.Children) { - statement.AcceptVisitor(this, null); + using(LogEval(expressionStatement)) { + EvalAndPermRef(expressionStatement.Expression); + return null; } - return null; } - public override object VisitEmptyStatement(EmptyStatement emptyStatement, object data) + public override object VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression, object data) { - return null; + Value cached; + if (TryGetCached(parenthesizedExpression, out cached)) return cached; + using(LogEval(parenthesizedExpression)) { + Value res = EvalAndPermRef(parenthesizedExpression.Expression); + + AddToCache(parenthesizedExpression, res); + return res; + } } - public override object VisitExpressionStatement(ExpressionStatement expressionStatement, object data) + public override object VisitBlockStatement(BlockStatement blockStatement, object data) { - expressionStatement.Expression.AcceptVisitor(this, null); - return null; + using(LogEval(blockStatement)) { + foreach(INode statement in blockStatement.Children) { + EvalAndPermRef(statement); + } + return null; + } } - public override object VisitIdentifierExpression(IdentifierExpression identifierExpression, object data) + /// We have to put that in cache as well otherwise expaning (a = b).Prop will reevalute + public override object VisitAssignmentExpression(AssignmentExpression assignmentExpression, object data) { - string identifier = identifierExpression.Identifier; - - if (identifier == "__exception") { - if (context.Thread.CurrentException != null) { - return context.Thread.CurrentException.Value; + Value cached; + if (TryGetCached(assignmentExpression, out cached)) return cached; + using(LogEval(assignmentExpression)) { + BinaryOperatorType op; + switch (assignmentExpression.Op) { + case AssignmentOperatorType.Assign: op = BinaryOperatorType.None; break; + case AssignmentOperatorType.Add: op = BinaryOperatorType.Add; break; + case AssignmentOperatorType.ConcatString: op = BinaryOperatorType.Concat; break; + case AssignmentOperatorType.Subtract: op = BinaryOperatorType.Subtract; break; + case AssignmentOperatorType.Multiply: op = BinaryOperatorType.Multiply; break; + case AssignmentOperatorType.Divide: op = BinaryOperatorType.Divide; break; + case AssignmentOperatorType.DivideInteger: op = BinaryOperatorType.DivideInteger; break; + case AssignmentOperatorType.ShiftLeft: op = BinaryOperatorType.ShiftLeft; break; + case AssignmentOperatorType.ShiftRight: op = BinaryOperatorType.ShiftRight; break; + case AssignmentOperatorType.ExclusiveOr: op = BinaryOperatorType.ExclusiveOr; break; + case AssignmentOperatorType.Modulus: op = BinaryOperatorType.Modulus; break; + case AssignmentOperatorType.BitwiseAnd: op = BinaryOperatorType.BitwiseAnd; break; + case AssignmentOperatorType.BitwiseOr: op = BinaryOperatorType.BitwiseOr; break; + case AssignmentOperatorType.Power: op = BinaryOperatorType.Power; break; + default: throw new GetValueException("Unknown operator " + assignmentExpression.Op); + } + + Value right; + if (op == BinaryOperatorType.None) { + right = EvalAndPermRef(assignmentExpression.Right); } else { - throw new GetValueException("No current exception"); + BinaryOperatorExpression binOpExpr = new BinaryOperatorExpression(); + binOpExpr.Left = assignmentExpression.Left; + binOpExpr.Op = op; + binOpExpr.Right = assignmentExpression.Right; + right = (Value)VisitBinaryOperatorExpression(binOpExpr, null); + } + right = right.GetPermanentReference(); + + Value left = EvalAndPermRef(assignmentExpression.Left); + + if (!left.IsReference && left.Type.FullName != right.Type.FullName) { + throw new GetValueException(string.Format("Type {0} expected, {1} seen", left.Type.FullName, right.Type.FullName)); } + left.SetValue(right); + + AddToCache(assignmentExpression, right); + return right; } - - Value arg = context.GetArgumentValue(identifier); - if (arg != null) return arg; - - Value local = context.GetLocalVariableValue(identifier); - if (local != null) return local; - - if (!context.MethodInfo.IsStatic) { - Value member = context.GetThisValue().GetMemberValue(identifier); - if (member != null) return member; - } else { - MemberInfo memberInfo = context.MethodInfo.DeclaringType.GetMember(identifier); - if (memberInfo != null && memberInfo.IsStatic) { - return Value.GetMemberValue(null, memberInfo, null); + } + + public override object VisitIdentifierExpression(IdentifierExpression identifierExpression, object data) + { + Value cached; + if (TryGetCached(identifierExpression, out cached)) return cached; + using(LogEval(identifierExpression)) { + string identifier = identifierExpression.Identifier; + + Value result = null; + + if (identifier == "__exception") { + if (context.Thread.CurrentException != null) { + result = context.Thread.CurrentException.Value; + } else { + throw new GetValueException("No current exception"); + } } + + result = result ?? context.GetArgumentValue(identifier); + + result = result ?? context.GetLocalVariableValue(identifier); + + if (result == null) { + if (!context.MethodInfo.IsStatic) { + // Can be null + result = context.GetThisValue().GetMemberValue(identifier); + } else { + MemberInfo memberInfo = context.MethodInfo.DeclaringType.GetMember(identifier); + if (memberInfo != null && memberInfo.IsStatic) { + result = Value.GetMemberValue(null, memberInfo, null); + } + } + } + + if (result == null) + throw new GetValueException("Identifier \"" + identifier + "\" not found in this context"); + + AddToCache(identifierExpression, result); + return result; } - - throw new GetValueException("Identifier \"" + identifier + "\" not found in this context"); } public override object VisitIndexerExpression(IndexerExpression indexerExpression, object data) { - List indexes = new List(); - foreach(Expression indexExpr in indexerExpression.Indexes) { - Value indexValue = ((Value)indexExpr.AcceptVisitor(this, null)).GetPermanentReference(); - indexes.Add(indexValue); - } - - Value target = (Value)indexerExpression.TargetObject.AcceptVisitor(this, null); - - if (target.Type.IsArray) { - List intIndexes = new List(); - foreach(Value index in indexes) { - if (!index.Type.IsInteger) throw new GetValueException("Integer expected for indexer"); - intIndexes.Add((int)index.PrimitiveValue); + Value cached; + if (TryGetCached(indexerExpression, out cached)) return cached; + using(LogEval(indexerExpression)) { + List indexes = new List(); + foreach(Expression indexExpr in indexerExpression.Indexes) { + Value indexValue = EvalAndPermRef(indexExpr); + indexes.Add(indexValue); } - return target.GetArrayElement(intIndexes.ToArray()); - } - - if (target.Type.IsPrimitive && target.PrimitiveValue is string) { - if (indexes.Count == 1 && indexes[0].Type.IsInteger) { - int index = (int)indexes[0].PrimitiveValue; - return Eval.CreateValue(context.AppDomain, ((string)target.PrimitiveValue)[index]); - } else { - throw new GetValueException("Expected single integer index"); + + Value target = EvalAndPermRef(indexerExpression.TargetObject); + + if (target.Type.IsArray) { + List intIndexes = new List(); + foreach(Value index in indexes) { + if (!index.Type.IsInteger) throw new GetValueException("Integer expected for indexer"); + intIndexes.Add((int)index.PrimitiveValue); + } + return target.GetArrayElement(intIndexes.ToArray()); } + + if (target.Type.IsPrimitive && target.PrimitiveValue is string) { + if (indexes.Count == 1 && indexes[0].Type.IsInteger) { + int index = (int)indexes[0].PrimitiveValue; + return Eval.CreateValue(context.AppDomain, ((string)target.PrimitiveValue)[index]); + } else { + throw new GetValueException("Expected single integer index"); + } + } + + PropertyInfo pi = target.Type.GetProperty("Item"); + if (pi == null) throw new GetValueException("The object does not have an indexer property"); + Value result = target.GetPropertyValue(pi, indexes.ToArray()); + + AddToCache(indexerExpression, result); + return result; } - - PropertyInfo pi = target.Type.GetProperty("Item"); - if (pi == null) throw new GetValueException("The object does not have an indexer property"); - return target.GetPropertyValue(pi, indexes.ToArray()); } public override object VisitInvocationExpression(InvocationExpression invocationExpression, object data) { - Value target; - string methodName; - MemberReferenceExpression memberRef = invocationExpression.TargetObject as MemberReferenceExpression; - if (memberRef != null) { - target = ((Value)memberRef.TargetObject.AcceptVisitor(this, null)).GetPermanentReference(); - methodName = memberRef.MemberName; - } else { - IdentifierExpression ident = invocationExpression.TargetObject as IdentifierExpression; - if (ident != null) { - target = context.GetThisValue(); - methodName = ident.Identifier; + Value cached; + if (TryGetCached(invocationExpression, out cached)) return cached; + using(LogEval(invocationExpression)) { + Value target; + string methodName; + MemberReferenceExpression memberRef = invocationExpression.TargetObject as MemberReferenceExpression; + if (memberRef != null) { + target = EvalAndPermRef(memberRef.TargetObject); + methodName = memberRef.MemberName; } else { - throw new GetValueException("Member reference expected for method invocation"); + IdentifierExpression ident = invocationExpression.TargetObject as IdentifierExpression; + if (ident != null) { + target = context.GetThisValue(); + methodName = ident.Identifier; + } else { + throw new GetValueException("Member reference expected for method invocation"); + } } + List args = new List(); + foreach(Expression expr in invocationExpression.Arguments) { + args.Add(EvalAndPermRef(expr)); + } + MethodInfo method = target.Type.GetMember(methodName, BindingFlags.Method | BindingFlags.IncludeSuperType) as MethodInfo; + if (method == null) { + throw new GetValueException("Method " + methodName + " not found"); + } + Value result = target.InvokeMethod(method, args.ToArray()); + + AddToCache(invocationExpression, result); + return result; } - List args = new List(); - foreach(Expression expr in invocationExpression.Arguments) { - args.Add(((Value)expr.AcceptVisitor(this, null)).GetPermanentReference()); - } - MethodInfo method = target.Type.GetMember(methodName, BindingFlags.Method | BindingFlags.IncludeSuperType) as MethodInfo; - if (method == null) { - throw new GetValueException("Method " + methodName + " not found"); - } - return target.InvokeMethod(method, args.ToArray()); } public override object VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression, object data) { - Value target = (Value)memberReferenceExpression.TargetObject.AcceptVisitor(this, null); - Value member = target.GetMemberValue(memberReferenceExpression.MemberName); - if (member != null) { + Value cached; + if (TryGetCached(memberReferenceExpression, out cached)) return cached; + using(LogEval(memberReferenceExpression)) { + Value target = EvalAndPermRef(memberReferenceExpression.TargetObject); + Value member = target.GetMemberValue(memberReferenceExpression.MemberName); + if (member == null) + throw new GetValueException("Member \"" + memberReferenceExpression.MemberName + "\" not found"); + + AddToCache(memberReferenceExpression, member); return member; - } else { - throw new GetValueException("Member \"" + memberReferenceExpression.MemberName + "\" not found"); } } - public override object VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression, object data) - { - return parenthesizedExpression.Expression.AcceptVisitor(this, null); - } - public override object VisitPrimitiveExpression(PrimitiveExpression primitiveExpression, object data) { - return Eval.CreateValue(context.AppDomain, primitiveExpression.Value); + Value cached; + if (TryGetCached(primitiveExpression, out cached)) return cached; + using(LogEval(primitiveExpression)){ + Value result = Eval.CreateValue(context.AppDomain, primitiveExpression.Value); + + AddToCache(primitiveExpression, result); + return result; + } } public override object VisitThisReferenceExpression(ThisReferenceExpression thisReferenceExpression, object data) { - return context.GetThisValue(); + Value cached; + if (TryGetCached(thisReferenceExpression, out cached)) return cached; + using(LogEval(thisReferenceExpression)) { + Value result = context.GetThisValue(); + + AddToCache(thisReferenceExpression, result); + return result; + } } public override object VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, object data) { - Value value = ((Value)unaryOperatorExpression.Expression.AcceptVisitor(this, null)); - UnaryOperatorType op = unaryOperatorExpression.Op; - - if (op == UnaryOperatorType.Dereference) { - if (!value.Type.IsPointer) throw new GetValueException("Target object is not a pointer"); - return value.Dereference(); - } - - if (!value.Type.IsPrimitive) throw new GetValueException("Primitive value expected"); - - object val = value.PrimitiveValue; - - object result = null; - - // Bool operation - if (val is bool) { - bool a = Convert.ToBoolean(val); - switch (op) { - case UnaryOperatorType.Not: result = !a; break; + Value cached; + if (TryGetCached(unaryOperatorExpression, out cached)) return cached; + using(LogEval(unaryOperatorExpression)) { + Value value = EvalAndPermRef(unaryOperatorExpression.Expression); + UnaryOperatorType op = unaryOperatorExpression.Op; + + if (op == UnaryOperatorType.Dereference) { + if (!value.Type.IsPointer) throw new GetValueException("Target object is not a pointer"); + return value.Dereference(); } - } - - // Float operation - if (val is double || val is float) { - double a = Convert.ToDouble(val); - switch (op) { - case UnaryOperatorType.Minus: result = -a; break; - case UnaryOperatorType.Plus: result = +a; break; + + if (!value.Type.IsPrimitive) throw new GetValueException("Primitive value expected"); + + object val = value.PrimitiveValue; + + object result = null; + + // Bool operation + if (val is bool) { + bool a = Convert.ToBoolean(val); + switch (op) { + case UnaryOperatorType.Not: result = !a; break; + } } - } - - // Integer operation - if (val is byte || val is sbyte || val is int || val is uint || val is long || val is ulong) { - long a = Convert.ToInt64(val); - switch (op) { - case UnaryOperatorType.Decrement: result = a - 1; break; - case UnaryOperatorType.Increment: result = a + 1; break; - case UnaryOperatorType.PostDecrement: result = a; break; - case UnaryOperatorType.PostIncrement: result = a; break; - case UnaryOperatorType.Minus: result = -a; break; - case UnaryOperatorType.Plus: result = a; break; - case UnaryOperatorType.BitNot: result = ~a; break; + + // Float operation + if (val is double || val is float) { + double a = Convert.ToDouble(val); + switch (op) { + case UnaryOperatorType.Minus: result = -a; break; + case UnaryOperatorType.Plus: result = +a; break; + } } - switch (op) { - case UnaryOperatorType.Decrement: - case UnaryOperatorType.PostDecrement: - VisitAssignmentExpression(new AssignmentExpression(unaryOperatorExpression.Expression, AssignmentOperatorType.Subtract, new PrimitiveExpression(1)), null); - break; - case UnaryOperatorType.Increment: - case UnaryOperatorType.PostIncrement: - VisitAssignmentExpression(new AssignmentExpression(unaryOperatorExpression.Expression, AssignmentOperatorType.Add, new PrimitiveExpression(1)), null); - break; + + // Integer operation + if (val is byte || val is sbyte || val is int || val is uint || val is long || val is ulong) { + long a = Convert.ToInt64(val); + switch (op) { + case UnaryOperatorType.Decrement: result = a - 1; break; + case UnaryOperatorType.Increment: result = a + 1; break; + case UnaryOperatorType.PostDecrement: result = a; break; + case UnaryOperatorType.PostIncrement: result = a; break; + case UnaryOperatorType.Minus: result = -a; break; + case UnaryOperatorType.Plus: result = a; break; + case UnaryOperatorType.BitNot: result = ~a; break; + } + switch (op) { + case UnaryOperatorType.Decrement: + case UnaryOperatorType.PostDecrement: + VisitAssignmentExpression(new AssignmentExpression(unaryOperatorExpression.Expression, AssignmentOperatorType.Subtract, new PrimitiveExpression(1)), null); + break; + case UnaryOperatorType.Increment: + case UnaryOperatorType.PostIncrement: + VisitAssignmentExpression(new AssignmentExpression(unaryOperatorExpression.Expression, AssignmentOperatorType.Add, new PrimitiveExpression(1)), null); + break; + } } + + if (result == null) throw new GetValueException("Unsuppored unary expression " + op); + + Value res = Eval.CreateValue(context.AppDomain, result); + + AddToCache(unaryOperatorExpression, res); + return res; } - - if (result == null) throw new GetValueException("Unsuppored unary expression " + op); - - return Eval.CreateValue(context.AppDomain, result); } public override object VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, object data) { - Value left = ((Value)binaryOperatorExpression.Left.AcceptVisitor(this, null)).GetPermanentReference(); - Value right = ((Value)binaryOperatorExpression.Right.AcceptVisitor(this, null)).GetPermanentReference(); - - object result = VisitBinaryOperatorExpressionInternal(left, right, binaryOperatorExpression.Op); - // Conver long to int if possible - if (result is long && int.MinValue <= (long)result && (long)result <= int.MaxValue) result = (int)(long)result; - return Eval.CreateValue(context.AppDomain, result); + Value cached; + if (TryGetCached(binaryOperatorExpression, out cached)) return cached; + using(LogEval(binaryOperatorExpression)) { + Value left = EvalAndPermRef(binaryOperatorExpression.Left); + Value right = EvalAndPermRef(binaryOperatorExpression.Right); + + object result = VisitBinaryOperatorExpressionInternal(left, right, binaryOperatorExpression.Op); + // Conver long to int if possible + if (result is long && int.MinValue <= (long)result && (long)result <= int.MaxValue) result = (int)(long)result; + Value res = Eval.CreateValue(context.AppDomain, result); + + AddToCache(binaryOperatorExpression, res); + return res; + } } public object VisitBinaryOperatorExpressionInternal(Value leftValue, Value rightValue, BinaryOperatorType op) diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Internal/ManagedCallback.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Internal/ManagedCallback.cs index 5d43170974..695dff3b4f 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Internal/ManagedCallback.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Internal/ManagedCallback.cs @@ -240,14 +240,18 @@ namespace Debugger public void EvalException(ICorDebugAppDomain pAppDomain, ICorDebugThread pThread, ICorDebugEval corEval) { - EnterCallback(PausedReason.EvalComplete, "EvalException", pThread); + Eval eval = process.ActiveEvals[corEval]; + + EnterCallback(PausedReason.EvalComplete, "EvalException: " + eval.Description, pThread); HandleEvalComplete(pAppDomain, pThread, corEval, true); } public void EvalComplete(ICorDebugAppDomain pAppDomain, ICorDebugThread pThread, ICorDebugEval corEval) { - EnterCallback(PausedReason.EvalComplete, "EvalComplete", pThread); + Eval eval = process.ActiveEvals[corEval]; + + EnterCallback(PausedReason.EvalComplete, "EvalComplete: " + eval.Description, pThread); HandleEvalComplete(pAppDomain, pThread, corEval, false); } diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Util/CallbackOnDispose.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Util/CallbackOnDispose.cs new file mode 100644 index 0000000000..055ab34118 --- /dev/null +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Util/CallbackOnDispose.cs @@ -0,0 +1,46 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Diagnostics; +using System.Threading; + +namespace Debugger +{ + /// + /// Invokes a callback when this class is disposed. + /// + sealed class CallbackOnDispose : IDisposable + { + Action callback; + + public CallbackOnDispose(Action callback) + { + if (callback == null) + throw new ArgumentNullException("callback"); + this.callback = callback; + } + + public void Dispose() + { + Action action = Interlocked.Exchange(ref callback, null); + if (action != null) { + action(); + #if DEBUG + GC.SuppressFinalize(this); + #endif + } + } + + #if DEBUG + ~CallbackOnDispose() + { + Debug.Fail("CallbackOnDispose was finalized without being disposed."); + } + #endif + } +}