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..c549bbeb5c 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,49 +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) { - throw; - } 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; + return new ExpressionEvaluator(context).Evaluate(code, false); } public static string FormatValue(Value val) @@ -129,6 +93,32 @@ namespace Debugger } } + public Value Evaluate(INode expression) + { + return Evaluate(expression, true); + } + + public Value Evaluate(INode expression, bool permRef) + { + Stopwatch watch = new Stopwatch(); + watch.Start(); + + Value val; + try { + val = (Value)expression.AcceptVisitor(this, null); + if (val != null && permRef) + val = val.GetPermanentReference(); + } catch (GetValueException) { + throw; + } catch (NotImplementedException e) { + throw new GetValueException(expression, "Language feature not implemented: " + e.Message); + } finally { + watch.Stop(); + context.Process.TraceMessage("Evaluated: {0} in {1} ms total", expression.PrettyPrint(), watch.ElapsedMilliseconds); + } + + return val; + } StackFrame context; @@ -136,7 +126,7 @@ namespace Debugger get { return context; } } - public ExpressionEvaluator(StackFrame context) + ExpressionEvaluator(StackFrame context) { this.context = context; } @@ -164,18 +154,22 @@ namespace Debugger Value right; if (op == BinaryOperatorType.None) { - right = (Value)assignmentExpression.Right.AcceptVisitor(this, null); + right = Evaluate(assignmentExpression.Right); } else { BinaryOperatorExpression binOpExpr = new BinaryOperatorExpression(); binOpExpr.Left = assignmentExpression.Left; binOpExpr.Op = op; binOpExpr.Right = assignmentExpression.Right; - right = (Value)VisitBinaryOperatorExpression(binOpExpr, null); + right = Evaluate(binOpExpr); } - right = right.GetPermanentReference(); - Value left = ((Value)assignmentExpression.Left.AcceptVisitor(this, null)); + // We can not have perfRef because we need to be able to set the value + Value left = (Value)assignmentExpression.Left.AcceptVisitor(this, null); + if (left == null) { + // Can this happen? + throw new GetValueException(string.Format("\"{0}\" can not be set", assignmentExpression.Left.PrettyPrint())); + } 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)); } @@ -186,7 +180,7 @@ namespace Debugger public override object VisitBlockStatement(BlockStatement blockStatement, object data) { foreach(INode statement in blockStatement.Children) { - statement.AcceptVisitor(this, null); + Evaluate(statement); } return null; } @@ -198,7 +192,7 @@ namespace Debugger public override object VisitExpressionStatement(ExpressionStatement expressionStatement, object data) { - expressionStatement.Expression.AcceptVisitor(this, null); + Evaluate(expressionStatement.Expression); return null; } @@ -237,11 +231,11 @@ namespace Debugger { List indexes = new List(); foreach(Expression indexExpr in indexerExpression.Indexes) { - Value indexValue = ((Value)indexExpr.AcceptVisitor(this, null)).GetPermanentReference(); + Value indexValue = Evaluate(indexExpr); indexes.Add(indexValue); } - Value target = (Value)indexerExpression.TargetObject.AcceptVisitor(this, null); + Value target = Evaluate(indexerExpression.TargetObject); if (target.Type.IsArray) { List intIndexes = new List(); @@ -272,31 +266,31 @@ namespace Debugger string methodName; MemberReferenceExpression memberRef = invocationExpression.TargetObject as MemberReferenceExpression; if (memberRef != null) { - target = ((Value)memberRef.TargetObject.AcceptVisitor(this, null)).GetPermanentReference(); + target = Evaluate(memberRef.TargetObject); methodName = memberRef.MemberName; } else { IdentifierExpression ident = invocationExpression.TargetObject as IdentifierExpression; if (ident != null) { - target = context.GetThisValue(); + target = Evaluate(new ThisReferenceExpression()); 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(((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"); } + List args = new List(); + foreach(Expression expr in invocationExpression.Arguments) { + args.Add(Evaluate(expr)); + } return target.InvokeMethod(method, args.ToArray()); } public override object VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression, object data) { - Value target = (Value)memberReferenceExpression.TargetObject.AcceptVisitor(this, null); + Value target = Evaluate(memberReferenceExpression.TargetObject); Value member = target.GetMemberValue(memberReferenceExpression.MemberName); if (member != null) { return member; @@ -307,7 +301,7 @@ namespace Debugger public override object VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression, object data) { - return parenthesizedExpression.Expression.AcceptVisitor(this, null); + return Evaluate(parenthesizedExpression.Expression); } public override object VisitPrimitiveExpression(PrimitiveExpression primitiveExpression, object data) @@ -322,12 +316,12 @@ namespace Debugger public override object VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, object data) { - Value value = ((Value)unaryOperatorExpression.Expression.AcceptVisitor(this, null)); + Value value = Evaluate(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(); + return value.Dereference(); // TODO: Test } if (!value.Type.IsPrimitive) throw new GetValueException("Primitive value expected"); @@ -384,8 +378,8 @@ namespace Debugger 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(); + Value left = Evaluate(binaryOperatorExpression.Left); + Value right = Evaluate(binaryOperatorExpression.Right); object result = VisitBinaryOperatorExpressionInternal(left, right, binaryOperatorExpression.Op); // Conver long to int if possible