From 374470b84b23412fcc2e7c576c86a1a8d9718496 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Sun, 23 Aug 2009 11:14:20 +0000 Subject: [PATCH] Expression caching (second attempt) git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4760 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Src/Expressions/ExpressionEvaluator.cs | 98 +++++++++---------- .../Expressions/ExpressionExtensionMethods.cs | 1 + .../Project/Src/DebuggerTests.cs | 1 - 3 files changed, 50 insertions(+), 50 deletions(-) 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 dfdbaed412..0e0b532dfa 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 @@ -51,15 +51,7 @@ namespace Debugger if (context == null) throw new ArgumentNullException("context"); if (context.IsInvalid) throw new DebuggerException("The context is no longer valid"); - Value result; - 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); - } - return result; + return new ExpressionEvaluator(context).Evaluate(code, false); } public static string FormatValue(Value val) @@ -101,36 +93,40 @@ namespace Debugger } } - void AddToCache(INode expression, Value value) + public Value Evaluate(INode expression) { - // Expressions are cleared then the process is resumed - context.Process.CachedExpressions[expression] = value; + return Evaluate(expression, true); } - bool TryGetCached(INode expression, out Value cached) + public Value Evaluate(INode expression, bool permRef) { + // Try to get the value from cache + // (the cache is cleared when the process is resumed) 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; + return val; } } - cached = null; - return false; - } - - Value EvalAndCache(INode expression, bool permRef) - { + Stopwatch watch = new Stopwatch(); watch.Start(); - Value val = (Value)expression.AcceptVisitor(this, null); - if (val != null && permRef) - val = val.GetPermanentReference(); - AddToCache(expression, val); - watch.Stop(); - context.Process.TraceMessage("Evaluated: {0} in {1} ms total", expression.PrettyPrint(), watch.ElapsedMilliseconds); + 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); + } + + // Add the result to cache + context.Process.CachedExpressions[expression] = val; + return val; } @@ -140,7 +136,7 @@ namespace Debugger get { return context; } } - public ExpressionEvaluator(StackFrame context) + ExpressionEvaluator(StackFrame context) { this.context = context; } @@ -168,18 +164,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)); } @@ -190,7 +190,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; } @@ -202,7 +202,7 @@ namespace Debugger public override object VisitExpressionStatement(ExpressionStatement expressionStatement, object data) { - expressionStatement.Expression.AcceptVisitor(this, null); + Evaluate(expressionStatement.Expression); return null; } @@ -241,11 +241,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(); @@ -276,31 +276,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; @@ -311,7 +311,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) @@ -326,12 +326,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"); @@ -388,8 +388,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 diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Expressions/ExpressionExtensionMethods.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Expressions/ExpressionExtensionMethods.cs index 41de5e3f2c..36f51b6910 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Expressions/ExpressionExtensionMethods.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Expressions/ExpressionExtensionMethods.cs @@ -58,6 +58,7 @@ namespace Debugger public static string PrettyPrint(this INode code) { + if (code == null) return string.Empty; CSharpOutputVisitor csOutVisitor = new CSharpOutputVisitor(); code.AcceptVisitor(csOutVisitor, null); return csOutVisitor.Text; diff --git a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/DebuggerTests.cs b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/DebuggerTests.cs index 4b7d76ec1c..e09fd97743 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/DebuggerTests.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/DebuggerTests.cs @@ -22,7 +22,6 @@ using NIgnore = NUnit.Framework.IgnoreAttribute; namespace Debugger.Tests { [TestFixture] - [NIgnore] public partial class DebuggerTests: DebuggerTestsBase {