From 2cabe3baf6b1424cb23db384cdd634e4512a785c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Sat, 4 Nov 2006 22:12:43 +0000 Subject: [PATCH] Reduce ValueProxy git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@2023 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Src/Service/DynamicTreeDebuggerRow.cs | 2 +- .../Project/Debugger.Core.csproj | 4 +- .../Project/Src/Variables/ArrayValue.cs | 12 +- .../Project/Src/Variables/NullValue.cs | 9 +- .../Project/Src/Variables/ObjectValue.cs | 12 +- .../Project/Src/Variables/ObjectValueClass.cs | 12 +- .../Project/Src/Variables/PrimitiveValue.cs | 12 +- .../Project/Src/Variables/Value.cs | 426 ++++++++++++++---- .../Project/Src/Variables/ValueProxy.cs | 93 ++++ .../Project/Src/Variables/Variable.cs | 335 ++------------ .../Project/Src/Variables/Variable2.cs | 91 ---- 11 files changed, 500 insertions(+), 508 deletions(-) create mode 100644 src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ValueProxy.cs delete mode 100644 src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Variable2.cs diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Service/DynamicTreeDebuggerRow.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Service/DynamicTreeDebuggerRow.cs index 1a248e4772..0dca2c514f 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Service/DynamicTreeDebuggerRow.cs +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Service/DynamicTreeDebuggerRow.cs @@ -88,7 +88,7 @@ namespace ICSharpCode.SharpDevelop.Services image = DebuggerIcons.GetImage(variable); this[1].Text = ""; // Icon this[2].Text = variable.Name; - if (ShowValuesInHexadecimal && variable.ValueProxy is PrimitiveValue && variable.ValueProxy.IsInteger) { + if (ShowValuesInHexadecimal && variable.ValueProxy is PrimitiveValue && variable.ValueProxy.TheValue.IsInteger) { this[3].Text = String.Format("0x{0:X}", (variable.ValueProxy as PrimitiveValue).Primitive); } else { this[3].Text = variable.ValueProxy.AsString; 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 03d7103334..f7cc1b6ac2 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Debugger.Core.csproj +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Debugger.Core.csproj @@ -377,18 +377,18 @@ - - + + diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ArrayValue.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ArrayValue.cs index d2aeaa0120..449ddb2d55 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ArrayValue.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ArrayValue.cs @@ -23,7 +23,7 @@ namespace Debugger protected ICorDebugArrayValue CorArrayValue { get { - return this.CorValue.CastTo(); + return TheValue.CorValue.CastTo(); } } @@ -35,7 +35,7 @@ namespace Debugger public string ElementsType { get { - return CorTypeToString(corElementType); + return Value.CorTypeToString(corElementType); } } @@ -72,7 +72,7 @@ namespace Debugger bool IsCorValueCompatible { get { - ArrayValue freshValue = this.FreshValue as ArrayValue; + ArrayValue freshValue = TheValue.ValueProxy as ArrayValue; return freshValue != null && freshValue.ElementsType == this.ElementsType && freshValue.Lenght == this.Lenght && @@ -119,9 +119,9 @@ namespace Debugger elementName, indices, new Value( - Process, - new IExpirable[] {this.Value}, - new IMutable[] {this.Value}, + TheValue.Process, + new IExpirable[] {this.TheValue}, + new IMutable[] {this.TheValue}, delegate { return GetCorValueOfItem(indices); } ) ); diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/NullValue.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/NullValue.cs index 803cb3a6e8..e0fb81ad0d 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/NullValue.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/NullValue.cs @@ -17,12 +17,9 @@ namespace Debugger } } - public override string Type - { - get - { - switch (CorType) - { + public override string Type { + get { + switch (TheValue.CorType) { case CorElementType.SZARRAY: case CorElementType.ARRAY: return typeof(System.Array).ToString(); case CorElementType.OBJECT: return typeof(System.Object).ToString(); diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ObjectValue.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ObjectValue.cs index d81e27595b..9b1e4f9e7c 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ObjectValue.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ObjectValue.cs @@ -68,20 +68,20 @@ namespace Debugger internal ObjectValue(Value @value):base(@value) { - topClass = new ObjectValueClass(this, this.CorValue.As().Class); + topClass = new ObjectValueClass(this, TheValue.CorValue.As().Class); Module module = GetClass("System.Object").Module; ICorDebugFunction corFunction = module.GetMethod("System.Object", "ToString", 0); - toStringText = new CallFunctionEval(this.Process, - new IExpirable[] {this.Value}, - new IMutable[] {this.Value}, + toStringText = new CallFunctionEval(TheValue.Process, + new IExpirable[] {this.TheValue}, + new IMutable[] {this.TheValue}, corFunction, - this.Value, + TheValue, new Value[] {}); } internal bool IsCorValueCompatible { get { - ObjectValue freshValue = this.FreshValue as ObjectValue; + ObjectValue freshValue = TheValue.ValueProxy as ObjectValue; return freshValue != null && topClass.Module == freshValue.TopClass.Module && topClass.ClassToken == freshValue.TopClass.ClassToken; diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ObjectValueClass.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ObjectValueClass.cs index 58bf45c827..e91248abf5 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ObjectValueClass.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ObjectValueClass.cs @@ -24,7 +24,7 @@ namespace Debugger ICorDebugObjectValue CorObjectValue { get { - return objectValue.CorValue.As(); + return objectValue.TheValue.CorValue.As(); } } @@ -60,7 +60,7 @@ namespace Debugger public ObjectValueClass(ObjectValue objectValue, ICorDebugClass corClass) { - this.process = objectValue.Process; + this.process = objectValue.TheValue.Process; this.objectValue = objectValue; this.module = process.GetModule(corClass.Module); this.corClass = corClass; @@ -139,8 +139,8 @@ namespace Debugger (field.IsPublic ? ObjectMember.Flags.Public : ObjectMember.Flags.None), new Value( process, - new IExpirable[] {this.objectValue.Value}, - new IMutable[] {this.objectValue.Value}, + new IExpirable[] {this.objectValue.TheValue}, + new IMutable[] {this.objectValue.TheValue}, delegate { return GetCorValueOfField(field); } ) ); @@ -186,10 +186,10 @@ namespace Debugger flags, new CallFunctionEval( process, - new IExpirable[] {this.objectValue.Value}, + new IExpirable[] {this.objectValue.TheValue}, new IMutable[] {process.DebugeeState}, Module.CorModule.GetFunctionFromToken(method.Token), - method.IsStatic ? null : this.objectValue.Value, // this + method.IsStatic ? null : this.objectValue.TheValue, // this new Value[] {} ) ); // args diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/PrimitiveValue.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/PrimitiveValue.cs index 00bf90dc99..a5cc79698b 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/PrimitiveValue.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/PrimitiveValue.cs @@ -25,10 +25,10 @@ namespace Debugger public object Primitive { get { - if (CorType == CorElementType.STRING) { - return (CorValue.CastTo()).String; + if (TheValue.CorType == CorElementType.STRING) { + return (TheValue.CorValue.CastTo()).String; } else { - return (CorValue.CastTo()).Value; + return (TheValue.CorValue.CastTo()).Value; } } set { @@ -40,12 +40,12 @@ namespace Debugger throw new NotSupportedException("Can not convert " + value.GetType().ToString() + " to " + ManagedType.ToString()); } - if (CorType == CorElementType.STRING) { + if (TheValue.CorType == CorElementType.STRING) { throw new NotSupportedException(); } else { - (CorValue.CastTo()).Value = newValue; + (TheValue.CorValue.CastTo()).Value = newValue; } - this.Value.NotifyChange(); + TheValue.NotifyChange(); } } diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Value.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Value.cs index 257fc9c04f..8c8fcabb8d 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Value.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Value.cs @@ -1,124 +1,407 @@ -// +// // // -// +// // $Revision$ // using System; +using System.Collections.Generic; + using Debugger.Wrappers.CorDebug; namespace Debugger { - public abstract class ValueProxy: RemotingObjectBase + /// + /// Delegate that is used to get value. This delegate may be called at any time and should never return null. + /// + delegate ICorDebugValue CorValueGetter(); + + /// + /// Value is a container which holds data necessaty to obtain + /// the value of a given object even after continue. This level of + /// abstraction is necessary because the type of a value can change + /// (eg for local variable of type object) + /// + /// Expiration: Once value expires it can not be used anymore. + /// Expiration is permanet - once value expires it stays expired. + /// Value expires when any object specified in constructor expires + /// or when process exits. + /// + /// Mutation: As long as any dependecy does not mutate the last + /// obteined value is still considered up to date. (If continue is + /// called and internal value is neutred new copy will be obatined) + /// + public class Value: IExpirable, IMutable { - Value val; + protected Process process; + + CorValueGetter corValueGetter; + IMutable[] mutateDependencies; + + protected ValueProxy currentValue; + protected ICorDebugValue currentCorValue; + protected PauseSession currentCorValuePauseSession; + + bool isExpired = false; + + public event EventHandler Expired; + public event EventHandler Changed; public Process Process { get { - return val.Process; + return process; } } - public Value Value { + public ICorDebugValue CorValue { get { - return val; + return DereferenceUnbox(RawCorValue); } } - internal ICorDebugValue CorValue { + internal CorElementType CorType { get { - return val.CorValue; + return GetCorType(this.CorValue); } } - protected ValueProxy FreshValue { - get { - return val.ValueProxy; + internal static CorElementType GetCorType(ICorDebugValue corValue) + { + if (corValue == null) { + return (CorElementType)0; } + return (CorElementType)corValue.Type; } - internal CorElementType CorType { + protected virtual ICorDebugValue RawCorValue { get { - return GetCorType(CorValue); + if (this.HasExpired) throw new CannotGetValueException("CorValue has expired"); + if (currentCorValue == null || (currentCorValuePauseSession != process.PauseSession && !currentCorValue.Is())) { + currentCorValue = corValueGetter(); + currentCorValuePauseSession = process.PauseSession; + } + return currentCorValue; } } - public abstract string AsString { - get; - } - - public virtual string Type { - get{ - return CorTypeToString(CorType); - } + public ValueProxy ValueProxy { + get { + if (currentValue == null) { + try { + currentValue = CreateValue(); + } catch (CannotGetValueException e) { + currentValue = new UnavailableValue(this, e.Message); + } + } + return currentValue; + } } - public virtual Type ManagedType { + public bool HasExpired { get { - return CorTypeToManagedType(CorType); + return isExpired; } } - public bool MayHaveSubVariables { + public ICorDebugValue SoftReference { get { - #if DEBUG - return true; - #else - return GetMayHaveSubVariables(); - #endif + if (this.HasExpired) throw new DebuggerException("CorValue has expired"); + + ICorDebugValue corValue = RawCorValue; + if (corValue != null && corValue.Is()) { + return corValue; + } + corValue = DereferenceUnbox(corValue); + if (corValue != null && corValue.Is()) { + return corValue.As().CreateHandle(CorDebugHandleType.HANDLE_WEAK_TRACK_RESURRECTION).CastTo(); + } else { + return corValue; // Value type - return value type + } } } - protected abstract bool GetMayHaveSubVariables(); + internal Value(Process process, + IExpirable[] expireDependencies, + IMutable[] mutateDependencies, + CorValueGetter corValueGetter) + { + this.process = process; + + foreach(IExpirable exp in expireDependencies) { + AddExpireDependency(exp); + } + AddExpireDependency(process); + + this.mutateDependencies = mutateDependencies; + if (!this.HasExpired) { + foreach(IMutable mut in mutateDependencies) { + AddMutateDependency(mut); + } + } + + this.corValueGetter = corValueGetter; + } - public VariableCollection SubVariables { - get { - VariableCollection subVars = GetSubVariables(); - #if DEBUG - return new VariableCollection(subVars.Name, - subVars.Value, - Util.MergeLists(val.GetDebugInfo(), subVars.SubCollections).ToArray(), - subVars.Items); - #else - return subVars; - #endif + void AddExpireDependency(IExpirable dependency) + { + if (dependency.HasExpired) { + MakeExpired(); + } else { + dependency.Expired += delegate { MakeExpired(); }; } } - protected virtual VariableCollection GetSubVariables() + void AddMutateDependency(IMutable dependency) { - return new VariableCollection(new Variable[] {}); + dependency.Changed += DependencyChanged; } - public Variable this[string variableName] { - get { - foreach(Variable v in SubVariables) { - if (v.Name == variableName) return v; + void MakeExpired() + { + if (!isExpired) { + isExpired = true; + OnExpired(new ValueEventArgs(this)); + foreach(IMutable mut in mutateDependencies) { + mut.Changed -= DependencyChanged; } - throw new DebuggerException("Subvariable " + variableName + " does not exist"); } } - protected ValueProxy(Value @value) + void DependencyChanged(object sender, ProcessEventArgs e) { - if (@value == null) throw new ArgumentNullException("value"); - this.val = @value; + NotifyChange(); } - public override string ToString() + protected virtual void ClearCurrentValue() { - return AsString; + currentValue = null; + currentCorValue = null; + currentCorValuePauseSession = null; } - internal static CorElementType GetCorType(ICorDebugValue corValue) + internal void NotifyChange() + { + ClearCurrentValue(); + if (!isExpired) { + OnChanged(new ValueEventArgs(this)); + } + } + + protected virtual void OnChanged(ProcessEventArgs e) + { + if (Changed != null) { + Changed(this, e); + } + } + + protected virtual void OnExpired(EventArgs e) + { + if (Expired != null) { + Expired(this, e); + } + } + + internal static ICorDebugValue DereferenceUnbox(ICorDebugValue corValue) { + // Method arguments can be passed 'by ref' + if (corValue.Type == (uint)CorElementType.BYREF) { + corValue = corValue.CastTo().Dereference(); + } + + // Pointers may be used in 'unsafe' code - CorElementType.PTR + // Classes need to be dereferenced + while (corValue.Is()) { + ICorDebugReferenceValue refValue = corValue.CastTo(); + if (refValue.IsNull != 0) { + return null; // Reference is null + } else { + try { + corValue = refValue.Dereference(); + // TODO: Investigate: Must not acutally be null + // eg. Assembly.AssemblyHandle See SD2-1117 + if (corValue == null) return null; // Dereference() returned null + } catch { + return null; // Error during dereferencing + } + } + } + + // Unbox value types + if (corValue.Is()) { + corValue = corValue.CastTo().Object.CastTo(); + } + + return corValue; + } + + public enum ValueType {Null, Primitive, Array, Object, Unknown}; + + ValueType GetValueType() + { + ICorDebugValue corValue = this.CorValue; + if (corValue == null) { - return (CorElementType)0; + return ValueType.Null; + } + + switch(GetCorType(corValue)) { + case CorElementType.BOOLEAN: + case CorElementType.CHAR: + case CorElementType.I1: + case CorElementType.U1: + case CorElementType.I2: + case CorElementType.U2: + case CorElementType.I4: + case CorElementType.U4: + case CorElementType.I8: + case CorElementType.U8: + case CorElementType.R4: + case CorElementType.R8: + case CorElementType.I: + case CorElementType.U: + case CorElementType.STRING: + return ValueType.Primitive; + + case CorElementType.ARRAY: + case CorElementType.SZARRAY: // Short-cut for single dimension zero lower bound array + return ValueType.Array; + + case CorElementType.VALUETYPE: + case CorElementType.CLASS: + case CorElementType.OBJECT: // Short-cut for Class "System.Object" + return ValueType.Object; + + default: // Unknown type + return ValueType.Unknown; } - return (CorElementType)corValue.Type; } - + + ValueProxy CreateValue() + { + ICorDebugValue corValue = this.CorValue; + + switch(GetValueType()) { + case ValueType.Null: return new NullValue(this); + case ValueType.Primitive: return new PrimitiveValue(this); + case ValueType.Array: return new ArrayValue(this); + case ValueType.Object: return new ObjectValue(this); + default: throw new CannotGetValueException("Unknown value type"); + } + } + + public bool SetValue(Value newValue) + { + ICorDebugValue corValue = this.RawCorValue; + ICorDebugValue newCorValue = newValue.RawCorValue; + if (newCorValue.Type == (uint)CorElementType.BYREF) { + newCorValue = newCorValue.As().Dereference(); + } + + if (corValue.Is()) { + if (newCorValue.Is()) { + ICorDebugClass corClass = newCorValue.As().Class; + ICorDebugValue box = Eval.NewObject(process, corClass).RawCorValue; + newCorValue = box; + } + corValue.CastTo().SetValue(newCorValue.CastTo().Value); + return true; + } else { + return false; + } + } + + /// + /// Returns true if the value is signed or unsigned integer of any size + /// + public bool IsInteger { + get { + CorElementType corType = CorType; + return corType == CorElementType.I1 || + corType == CorElementType.U1 || + corType == CorElementType.I2 || + corType == CorElementType.U2 || + corType == CorElementType.I4 || + corType == CorElementType.U4 || + corType == CorElementType.I8 || + corType == CorElementType.U8 || + corType == CorElementType.I || + corType == CorElementType.U; + } + } + + public VariableCollection GetDebugInfo() + { + return GetDebugInfo(this.RawCorValue); + } + + public static VariableCollection GetDebugInfo(ICorDebugValue corValue) + { + List items = new List(); + + if (corValue.Is()) { + List more = new List(); + more.Add(new VariableCollection("type", ((CorElementType)corValue.Type).ToString())); + more.Add(new VariableCollection("size", corValue.Size.ToString())); + more.Add(new VariableCollection("address", corValue.Address.ToString("X"))); + items.Add(new VariableCollection("ICorDebugValue", "", more, null)); + } + if (corValue.Is()) items.Add(new VariableCollection("ICorDebugValue2", "", null, null)); + if (corValue.Is()) { + List more = new List(); + try { + byte[] bytes = corValue.CastTo().RawValue; + for(int i = 0; i < bytes.Length; i += 8) { + string val = ""; + for(int j = i; j < bytes.Length && j < i + 8; j++) { + val += bytes[j].ToString("X2") + " "; + } + more.Add(new VariableCollection("data" + i.ToString("X2"), val)); + } + } catch (ArgumentException) { + more.Add(new VariableCollection("data", "N/A")); + } + items.Add(new VariableCollection("ICorDebugGenericValue", "", more, null)); + } + if (corValue.Is()) { + List more = new List(); + ICorDebugReferenceValue refValue = corValue.CastTo(); + bool isNull = refValue.IsNull != 0; + more.Add(new VariableCollection("isNull", isNull.ToString())); + if (!isNull) { + more.Add(new VariableCollection("address", refValue.Value.ToString("X"))); + if (refValue.Dereference() != null) { + VariableCollection deRef = GetDebugInfo(refValue.Dereference()); + more.Add(new VariableCollection("dereferenced", deRef.Value, deRef.SubCollections, deRef.Items)); + } else { + more.Add(new VariableCollection("dereferenced", "N/A", null, null)); + } + + } + items.Add(new VariableCollection("ICorDebugReferenceValue", "", more, null)); + } + if (corValue.Is()) items.Add(new VariableCollection("ICorDebugHeapValue", "", null, null)); + if (corValue.Is()) items.Add(new VariableCollection("ICorDebugHeapValue2", "", null, null)); + if (corValue.Is()) { + List more = new List(); + bool isValue = corValue.CastTo().IsValueClass != 0; + more.Add(new VariableCollection("isValue", isValue.ToString())); + items.Add(new VariableCollection("ICorDebugObjectValue", "", more, null)); + } + if (corValue.Is()) items.Add(new VariableCollection("ICorDebugObjectValue2", "", null, null)); + if (corValue.Is()) { + List more = new List(); + VariableCollection unboxed = GetDebugInfo(corValue.CastTo().Object.CastTo()); + more.Add(new VariableCollection("unboxed", unboxed.Value, unboxed.SubCollections, unboxed.Items)); + items.Add(new VariableCollection("ICorDebugBoxValue", "", more, null)); + } + if (corValue.Is()) items.Add(new VariableCollection("ICorDebugStringValue", "", null, null)); + if (corValue.Is()) items.Add(new VariableCollection("ICorDebugArrayValue", "", null, null)); + if (corValue.Is()) items.Add(new VariableCollection("ICorDebugHandleValue", "", null, null)); + + return new VariableCollection("$debugInfo", ((CorElementType)corValue.Type).ToString(), items.ToArray(), null); + } + internal static System.Type CorTypeToManagedType(CorElementType corType) { switch(corType) @@ -145,25 +428,6 @@ namespace Debugger } } - /// - /// Returns true if the value is signed or unsigned integer of any size - /// - public bool IsInteger { - get { - CorElementType corType = CorType; - return corType == CorElementType.I1 || - corType == CorElementType.U1 || - corType == CorElementType.I2 || - corType == CorElementType.U2 || - corType == CorElementType.I4 || - corType == CorElementType.U4 || - corType == CorElementType.I8 || - corType == CorElementType.U8 || - corType == CorElementType.I || - corType == CorElementType.U; - } - } - internal static string CorTypeToString(CorElementType corType) { Type manType = CorTypeToManagedType(corType); @@ -171,4 +435,12 @@ namespace Debugger return manType.ToString(); } } + + class CannotGetValueException: System.Exception + { + public CannotGetValueException(string message):base(message) + { + + } + } } diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ValueProxy.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ValueProxy.cs new file mode 100644 index 0000000000..da645106b5 --- /dev/null +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ValueProxy.cs @@ -0,0 +1,93 @@ +// +// +// +// +// $Revision$ +// + +using System; +using Debugger.Wrappers.CorDebug; + +namespace Debugger +{ + /// + /// Provides more specific access + /// + public abstract class ValueProxy: RemotingObjectBase + { + Value val; + + public Value TheValue { + get { + return val; + } + } + + public abstract string AsString { + get; + } + + public virtual string Type { + get{ + return Value.CorTypeToString(TheValue.CorType); + } + } + + public virtual Type ManagedType { + get { + return Value.CorTypeToManagedType(TheValue.CorType); + } + } + + public bool MayHaveSubVariables { + get { + #if DEBUG + return true; + #else + return GetMayHaveSubVariables(); + #endif + } + } + + protected abstract bool GetMayHaveSubVariables(); + + public VariableCollection SubVariables { + get { + VariableCollection subVars = GetSubVariables(); + #if DEBUG + return new VariableCollection(subVars.Name, + subVars.Value, + Util.MergeLists(val.GetDebugInfo(), subVars.SubCollections).ToArray(), + subVars.Items); + #else + return subVars; + #endif + } + } + + protected virtual VariableCollection GetSubVariables() + { + return new VariableCollection(new Variable[] {}); + } + + public Variable this[string variableName] { + get { + foreach(Variable v in SubVariables) { + if (v.Name == variableName) return v; + } + throw new DebuggerException("Subvariable " + variableName + " does not exist"); + } + } + + protected ValueProxy(Value @value) + { + if (@value == null) throw new ArgumentNullException("value"); + this.val = @value; + } + + public override string ToString() + { + return AsString; + } + } +} diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Variable.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Variable.cs index 8f848d2fd5..0d18c1f3be 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Variable.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Variable.cs @@ -1,7 +1,7 @@ -// +// // // -// +// // $Revision$ // @@ -13,358 +13,79 @@ using Debugger.Wrappers.CorDebug; namespace Debugger { /// - /// Delegate that is used to get value. This delegate may be called at any time and should never return null. - /// - delegate ICorDebugValue CorValueGetter(); - - /// - /// Value is a container which holds data necessaty to obtain - /// the value of a given object even after continue. This level of - /// abstraction is necessary because the type of a value can change - /// (eg for local variable of type object) - /// - /// Value is a container for Variable which makes it possible to - /// access specific properties of current value (eg array) /// - /// Expiration: Once value expires it can not be used anymore. - /// Expiration is permanet - once value expires it stays expired. - /// Value expires when any object specified in constructor expires - /// or when process exits. - /// - /// Mutation: As long as any dependecy does not mutate the last - /// obteined value is still considered up to date. (If continue is - /// called and internal value is neutred new copy will be obatined) /// - public class Value: IExpirable, IMutable + public class Variable: IExpirable, IMutable { - protected Process process; - - CorValueGetter corValueGetter; - IMutable[] mutateDependencies; - - protected ValueProxy currentValue; - protected ICorDebugValue currentCorValue; - protected PauseSession currentCorValuePauseSession; - - bool isExpired = false; + string name; + Value val; + bool hasExpired; public event EventHandler Expired; public event EventHandler Changed; public Process Process { get { - return process; + return val.Process; } } - public ICorDebugValue CorValue { + public string Name { get { - return DereferenceUnbox(RawCorValue); + return name; } } - protected virtual ICorDebugValue RawCorValue { + public Value Value { get { - if (this.HasExpired) throw new CannotGetValueException("CorValue has expired"); - if (currentCorValue == null || (currentCorValuePauseSession != process.PauseSession && !currentCorValue.Is())) { - currentCorValue = corValueGetter(); - currentCorValuePauseSession = process.PauseSession; - } - return currentCorValue; + return val; } } public ValueProxy ValueProxy { get { - if (currentValue == null) { - try { - currentValue = CreateValue(); - } catch (CannotGetValueException e) { - currentValue = new UnavailableValue(this, e.Message); - } - } - return currentValue; + return val.ValueProxy; } } public bool HasExpired { get { - return isExpired; - } - } - - public ICorDebugValue SoftReference { - get { - if (this.HasExpired) throw new DebuggerException("CorValue has expired"); - - ICorDebugValue corValue = RawCorValue; - if (corValue != null && corValue.Is()) { - return corValue; - } - corValue = DereferenceUnbox(corValue); - if (corValue != null && corValue.Is()) { - return corValue.As().CreateHandle(CorDebugHandleType.HANDLE_WEAK_TRACK_RESURRECTION).CastTo(); - } else { - return corValue; // Value type - return value type - } + return hasExpired; } } - internal Value(Process process, - IExpirable[] expireDependencies, - IMutable[] mutateDependencies, - CorValueGetter corValueGetter) + internal Variable(string name, Value @value) { - this.process = process; + if (@value == null) throw new ArgumentNullException("value"); - foreach(IExpirable exp in expireDependencies) { - AddExpireDependency(exp); - } - AddExpireDependency(process); + this.name = name; + this.val = @value; + this.val.Expired += delegate(object sender, EventArgs e) { OnExpired(e); }; + this.val.Changed += delegate(object sender, ProcessEventArgs e) { OnChanged(e); }; - this.mutateDependencies = mutateDependencies; - if (!this.HasExpired) { - foreach(IMutable mut in mutateDependencies) { - AddMutateDependency(mut); + if (name.StartsWith("<") && name.Contains(">") && name != "") { + string middle = name.TrimStart('<').Split('>')[0]; // Get text between '<' and '>' + if (middle != "") { + this.name = middle; } } - - this.corValueGetter = corValueGetter; } - void AddExpireDependency(IExpirable dependency) - { - if (dependency.HasExpired) { - MakeExpired(); - } else { - dependency.Expired += delegate { MakeExpired(); }; - } - } - - void AddMutateDependency(IMutable dependency) - { - dependency.Changed += DependencyChanged; - } - - void MakeExpired() + protected virtual void OnExpired(EventArgs e) { - if (!isExpired) { - isExpired = true; - OnExpired(new ValueEventArgs(this)); - foreach(IMutable mut in mutateDependencies) { - mut.Changed -= DependencyChanged; + if (!hasExpired) { + hasExpired = true; + if (Expired != null) { + Expired(this, e); } } } - void DependencyChanged(object sender, ProcessEventArgs e) - { - NotifyChange(); - } - - protected virtual void ClearCurrentValue() - { - currentValue = null; - currentCorValue = null; - currentCorValuePauseSession = null; - } - - internal void NotifyChange() - { - ClearCurrentValue(); - if (!isExpired) { - OnChanged(new ValueEventArgs(this)); - } - } - protected virtual void OnChanged(ProcessEventArgs e) { if (Changed != null) { Changed(this, e); } } - - protected virtual void OnExpired(EventArgs e) - { - if (Expired != null) { - Expired(this, e); - } - } - - internal static ICorDebugValue DereferenceUnbox(ICorDebugValue corValue) - { - // Method arguments can be passed 'by ref' - if (corValue.Type == (uint)CorElementType.BYREF) { - corValue = corValue.CastTo().Dereference(); - } - - // Pointers may be used in 'unsafe' code - CorElementType.PTR - // Classes need to be dereferenced - while (corValue.Is()) { - ICorDebugReferenceValue refValue = corValue.CastTo(); - if (refValue.IsNull != 0) { - return null; // Reference is null - } else { - try { - corValue = refValue.Dereference(); - // TODO: Investigate: Must not acutally be null - // eg. Assembly.AssemblyHandle See SD2-1117 - if (corValue == null) return null; // Dereference() returned null - } catch { - return null; // Error during dereferencing - } - } - } - - // Unbox value types - if (corValue.Is()) { - corValue = corValue.CastTo().Object.CastTo(); - } - - return corValue; - } - - ValueProxy CreateValue() - { - ICorDebugValue corValue = this.CorValue; - - if (corValue == null) { - return new NullValue(this); - } - - CorElementType type = ValueProxy.GetCorType(corValue); - - switch(type) { - case CorElementType.BOOLEAN: - case CorElementType.CHAR: - case CorElementType.I1: - case CorElementType.U1: - case CorElementType.I2: - case CorElementType.U2: - case CorElementType.I4: - case CorElementType.U4: - case CorElementType.I8: - case CorElementType.U8: - case CorElementType.R4: - case CorElementType.R8: - case CorElementType.I: - case CorElementType.U: - case CorElementType.STRING: - return new PrimitiveValue(this); - - case CorElementType.ARRAY: - case CorElementType.SZARRAY: // Short-cut for single dimension zero lower bound array - return new ArrayValue(this); - - case CorElementType.VALUETYPE: - case CorElementType.CLASS: - case CorElementType.OBJECT: // Short-cut for Class "System.Object" - return new ObjectValue(this); - - default: // Unknown type - throw new CannotGetValueException("Unknown value type"); - } - } - - public bool SetValue(Value newValue) - { - ICorDebugValue corValue = this.RawCorValue; - ICorDebugValue newCorValue = newValue.RawCorValue; - if (newCorValue.Type == (uint)CorElementType.BYREF) { - newCorValue = newCorValue.As().Dereference(); - } - - if (corValue.Is()) { - if (newCorValue.Is()) { - ICorDebugClass corClass = newCorValue.As().Class; - ICorDebugValue box = Eval.NewObject(process, corClass).RawCorValue; - newCorValue = box; - } - corValue.CastTo().SetValue(newCorValue.CastTo().Value); - return true; - } else { - return false; - } - } - - public VariableCollection GetDebugInfo() - { - return GetDebugInfo(this.RawCorValue); - } - - public static VariableCollection GetDebugInfo(ICorDebugValue corValue) - { - List items = new List(); - - if (corValue.Is()) { - List more = new List(); - more.Add(new VariableCollection("type", ((CorElementType)corValue.Type).ToString())); - more.Add(new VariableCollection("size", corValue.Size.ToString())); - more.Add(new VariableCollection("address", corValue.Address.ToString("X"))); - items.Add(new VariableCollection("ICorDebugValue", "", more, null)); - } - if (corValue.Is()) items.Add(new VariableCollection("ICorDebugValue2", "", null, null)); - if (corValue.Is()) { - List more = new List(); - try { - byte[] bytes = corValue.CastTo().RawValue; - for(int i = 0; i < bytes.Length; i += 8) { - string val = ""; - for(int j = i; j < bytes.Length && j < i + 8; j++) { - val += bytes[j].ToString("X2") + " "; - } - more.Add(new VariableCollection("data" + i.ToString("X2"), val)); - } - } catch (ArgumentException) { - more.Add(new VariableCollection("data", "N/A")); - } - items.Add(new VariableCollection("ICorDebugGenericValue", "", more, null)); - } - if (corValue.Is()) { - List more = new List(); - ICorDebugReferenceValue refValue = corValue.CastTo(); - bool isNull = refValue.IsNull != 0; - more.Add(new VariableCollection("isNull", isNull.ToString())); - if (!isNull) { - more.Add(new VariableCollection("address", refValue.Value.ToString("X"))); - if (refValue.Dereference() != null) { - VariableCollection deRef = GetDebugInfo(refValue.Dereference()); - more.Add(new VariableCollection("dereferenced", deRef.Value, deRef.SubCollections, deRef.Items)); - } else { - more.Add(new VariableCollection("dereferenced", "N/A", null, null)); - } - - } - items.Add(new VariableCollection("ICorDebugReferenceValue", "", more, null)); - } - if (corValue.Is()) items.Add(new VariableCollection("ICorDebugHeapValue", "", null, null)); - if (corValue.Is()) items.Add(new VariableCollection("ICorDebugHeapValue2", "", null, null)); - if (corValue.Is()) { - List more = new List(); - bool isValue = corValue.CastTo().IsValueClass != 0; - more.Add(new VariableCollection("isValue", isValue.ToString())); - items.Add(new VariableCollection("ICorDebugObjectValue", "", more, null)); - } - if (corValue.Is()) items.Add(new VariableCollection("ICorDebugObjectValue2", "", null, null)); - if (corValue.Is()) { - List more = new List(); - VariableCollection unboxed = GetDebugInfo(corValue.CastTo().Object.CastTo()); - more.Add(new VariableCollection("unboxed", unboxed.Value, unboxed.SubCollections, unboxed.Items)); - items.Add(new VariableCollection("ICorDebugBoxValue", "", more, null)); - } - if (corValue.Is()) items.Add(new VariableCollection("ICorDebugStringValue", "", null, null)); - if (corValue.Is()) items.Add(new VariableCollection("ICorDebugArrayValue", "", null, null)); - if (corValue.Is()) items.Add(new VariableCollection("ICorDebugHandleValue", "", null, null)); - - return new VariableCollection("$debugInfo", ((CorElementType)corValue.Type).ToString(), items.ToArray(), null); - } - } - - class CannotGetValueException: System.Exception - { - public CannotGetValueException(string message):base(message) - { - - } } } diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Variable2.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Variable2.cs deleted file mode 100644 index 0d18c1f3be..0000000000 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Variable2.cs +++ /dev/null @@ -1,91 +0,0 @@ -// -// -// -// -// $Revision$ -// - -using System; -using System.Collections.Generic; - -using Debugger.Wrappers.CorDebug; - -namespace Debugger -{ - /// - /// - /// - public class Variable: IExpirable, IMutable - { - string name; - Value val; - bool hasExpired; - - public event EventHandler Expired; - public event EventHandler Changed; - - public Process Process { - get { - return val.Process; - } - } - - public string Name { - get { - return name; - } - } - - public Value Value { - get { - return val; - } - } - - public ValueProxy ValueProxy { - get { - return val.ValueProxy; - } - } - - public bool HasExpired { - get { - return hasExpired; - } - } - - internal Variable(string name, Value @value) - { - if (@value == null) throw new ArgumentNullException("value"); - - this.name = name; - this.val = @value; - this.val.Expired += delegate(object sender, EventArgs e) { OnExpired(e); }; - this.val.Changed += delegate(object sender, ProcessEventArgs e) { OnChanged(e); }; - - if (name.StartsWith("<") && name.Contains(">") && name != "") { - string middle = name.TrimStart('<').Split('>')[0]; // Get text between '<' and '>' - if (middle != "") { - this.name = middle; - } - } - } - - protected virtual void OnExpired(EventArgs e) - { - if (!hasExpired) { - hasExpired = true; - if (Expired != null) { - Expired(this, e); - } - } - } - - protected virtual void OnChanged(ProcessEventArgs e) - { - if (Changed != null) { - Changed(this, e); - } - } - } -}