Browse Source

Add cache for implicit conversions for 25% performance boost.

Also did some improvements to interning.
newNRvisualizers
Daniel Grunwald 15 years ago
parent
commit
2be1569cc7
  1. 10
      ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs
  2. 16
      ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs
  3. 50
      ICSharpCode.NRefactory/CSharp/Resolver/Conversions.cs
  4. 6
      ICSharpCode.NRefactory/CSharp/Resolver/MethodGroupResolveResult.cs
  5. 4
      ICSharpCode.NRefactory/CSharp/Resolver/OverloadResolution.cs
  6. 4
      ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs
  7. 38
      ICSharpCode.NRefactory/TypeSystem/ByReferenceType.cs
  8. 1
      ICSharpCode.NRefactory/TypeSystem/Implementation/CompoundTypeDefinition.cs
  9. 1
      ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultExplicitInterfaceImplementation.cs
  10. 38
      ICSharpCode.NRefactory/TypeSystem/PointerType.cs

10
ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs

@ -130,16 +130,22 @@ namespace ICSharpCode.NRefactory.CSharp
public override IEntity VisitUsingDeclaration(UsingDeclaration usingDeclaration, object data) public override IEntity VisitUsingDeclaration(UsingDeclaration usingDeclaration, object data)
{ {
ITypeOrNamespaceReference u = ConvertType(usingDeclaration.Import, SimpleNameLookupMode.TypeInUsingDeclaration) as ITypeOrNamespaceReference; ITypeOrNamespaceReference u = ConvertType(usingDeclaration.Import, SimpleNameLookupMode.TypeInUsingDeclaration) as ITypeOrNamespaceReference;
if (u != null) if (u != null) {
if (interningProvider != null)
u = interningProvider.Intern(u);
usingScope.Usings.Add(u); usingScope.Usings.Add(u);
}
return null; return null;
} }
public override IEntity VisitUsingAliasDeclaration(UsingAliasDeclaration usingDeclaration, object data) public override IEntity VisitUsingAliasDeclaration(UsingAliasDeclaration usingDeclaration, object data)
{ {
ITypeOrNamespaceReference u = ConvertType(usingDeclaration.Import, SimpleNameLookupMode.TypeInUsingDeclaration) as ITypeOrNamespaceReference; ITypeOrNamespaceReference u = ConvertType(usingDeclaration.Import, SimpleNameLookupMode.TypeInUsingDeclaration) as ITypeOrNamespaceReference;
if (u != null) if (u != null) {
if (interningProvider != null)
u = interningProvider.Intern(u);
usingScope.UsingAliases.Add(new KeyValuePair<string, ITypeOrNamespaceReference>(usingDeclaration.Alias, u)); usingScope.UsingAliases.Add(new KeyValuePair<string, ITypeOrNamespaceReference>(usingDeclaration.Alias, u));
}
return null; return null;
} }
#endregion #endregion

16
ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs

@ -539,7 +539,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
bool isNullable = NullableType.IsNullable(expression.Type); bool isNullable = NullableType.IsNullable(expression.Type);
// the operator is overloadable: // the operator is overloadable:
OverloadResolution userDefinedOperatorOR = new OverloadResolution(context, new[] { expression }); OverloadResolution userDefinedOperatorOR = new OverloadResolution(context, new[] { expression }, conversions: conversions);
foreach (var candidate in GetUserDefinedOperatorCandidates(type, overloadableOperatorName)) { foreach (var candidate in GetUserDefinedOperatorCandidates(type, overloadableOperatorName)) {
userDefinedOperatorOR.AddCandidate(candidate); userDefinedOperatorOR.AddCandidate(candidate);
} }
@ -587,7 +587,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
default: default:
throw new InvalidOperationException(); throw new InvalidOperationException();
} }
OverloadResolution builtinOperatorOR = new OverloadResolution(context, new[] { expression }); OverloadResolution builtinOperatorOR = new OverloadResolution(context, new[] { expression }, conversions: conversions);
foreach (var candidate in methodGroup) { foreach (var candidate in methodGroup) {
builtinOperatorOR.AddCandidate(candidate); builtinOperatorOR.AddCandidate(candidate);
} }
@ -800,7 +800,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
IType rhsType = NullableType.GetUnderlyingType(rhs.Type); IType rhsType = NullableType.GetUnderlyingType(rhs.Type);
// the operator is overloadable: // the operator is overloadable:
OverloadResolution userDefinedOperatorOR = new OverloadResolution(context, new[] { lhs, rhs }); OverloadResolution userDefinedOperatorOR = new OverloadResolution(context, new[] { lhs, rhs }, conversions: conversions);
HashSet<IParameterizedMember> userOperatorCandidates = new HashSet<IParameterizedMember>(); HashSet<IParameterizedMember> userOperatorCandidates = new HashSet<IParameterizedMember>();
userOperatorCandidates.UnionWith(GetUserDefinedOperatorCandidates(lhsType, overloadableOperatorName)); userOperatorCandidates.UnionWith(GetUserDefinedOperatorCandidates(lhsType, overloadableOperatorName));
userOperatorCandidates.UnionWith(GetUserDefinedOperatorCandidates(rhsType, overloadableOperatorName)); userOperatorCandidates.UnionWith(GetUserDefinedOperatorCandidates(rhsType, overloadableOperatorName));
@ -1016,7 +1016,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
default: default:
throw new InvalidOperationException(); throw new InvalidOperationException();
} }
OverloadResolution builtinOperatorOR = new OverloadResolution(context, new[] { lhs, rhs }); OverloadResolution builtinOperatorOR = new OverloadResolution(context, new[] { lhs, rhs }, conversions: conversions);
foreach (var candidate in methodGroup) { foreach (var candidate in methodGroup) {
builtinOperatorOR.AddCandidate(candidate); builtinOperatorOR.AddCandidate(candidate);
} }
@ -2240,7 +2240,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
MethodGroupResolveResult mgrr = target as MethodGroupResolveResult; MethodGroupResolveResult mgrr = target as MethodGroupResolveResult;
if (mgrr != null) { if (mgrr != null) {
OverloadResolution or = mgrr.PerformOverloadResolution(context, arguments, argumentNames); OverloadResolution or = mgrr.PerformOverloadResolution(context, arguments, argumentNames, conversions: conversions);
if (or.BestCandidate != null) { if (or.BestCandidate != null) {
return new InvocationResolveResult(mgrr.TargetResult, or, context); return new InvocationResolveResult(mgrr.TargetResult, or, context);
} else { } else {
@ -2260,7 +2260,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
} }
IMethod invokeMethod = target.Type.GetDelegateInvokeMethod(); IMethod invokeMethod = target.Type.GetDelegateInvokeMethod();
if (invokeMethod != null) { if (invokeMethod != null) {
OverloadResolution or = new OverloadResolution(context, arguments, argumentNames); OverloadResolution or = new OverloadResolution(context, arguments, argumentNames, conversions: conversions);
or.AddCandidate(invokeMethod); or.AddCandidate(invokeMethod);
return new InvocationResolveResult( return new InvocationResolveResult(
target, invokeMethod, invokeMethod.ReturnType.Resolve(context), target, invokeMethod, invokeMethod.ReturnType.Resolve(context),
@ -2386,7 +2386,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
} }
// §7.6.6.2 Indexer access // §7.6.6.2 Indexer access
OverloadResolution or = new OverloadResolution(context, arguments, argumentNames, new IType[0]); OverloadResolution or = new OverloadResolution(context, arguments, argumentNames, conversions: conversions);
MemberLookup lookup = CreateMemberLookup(); MemberLookup lookup = CreateMemberLookup();
var indexers = lookup.LookupIndexers(target.Type); var indexers = lookup.LookupIndexers(target.Type);
or.AddMethodLists(indexers); or.AddMethodLists(indexers);
@ -2435,7 +2435,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (type.Kind == TypeKind.Delegate && arguments.Length == 1) { if (type.Kind == TypeKind.Delegate && arguments.Length == 1) {
return Convert(arguments[0], type); return Convert(arguments[0], type);
} }
OverloadResolution or = new OverloadResolution(context, arguments, argumentNames, new IType[0]); OverloadResolution or = new OverloadResolution(context, arguments, argumentNames, conversions: conversions);
MemberLookup lookup = CreateMemberLookup(); MemberLookup lookup = CreateMemberLookup();
bool allowProtectedAccess = lookup.IsProtectedAccessAllowed(type); bool allowProtectedAccess = lookup.IsProtectedAccessAllowed(type);
var constructors = type.GetConstructors(context, m => lookup.IsAccessible(m, allowProtectedAccess)); var constructors = type.GetConstructors(context, m => lookup.IsAccessible(m, allowProtectedAccess));

50
ICSharpCode.NRefactory/CSharp/Resolver/Conversions.cs

@ -235,6 +235,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// </summary> /// </summary>
public class Conversions public class Conversions
{ {
readonly Dictionary<TypePair, Conversion> implicitConversionCache = new Dictionary<TypePair, Conversion>();
readonly ITypeResolveContext context; readonly ITypeResolveContext context;
readonly IType objectType; readonly IType objectType;
@ -247,6 +248,37 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
this.dynamicErasure = new DynamicErasure(this); this.dynamicErasure = new DynamicErasure(this);
} }
#region TypePair (for caching)
struct TypePair : IEquatable<TypePair>
{
public readonly IType FromType;
public readonly IType ToType;
public TypePair(IType fromType, IType toType)
{
this.FromType = fromType;
this.ToType = toType;
}
public override bool Equals(object obj)
{
return (obj is TypePair) && Equals((TypePair)obj);
}
public bool Equals(TypePair other)
{
return this.FromType.Equals(other.FromType) && this.ToType.Equals(other.ToType);
}
public override int GetHashCode()
{
unchecked {
return 1000000007 * FromType.GetHashCode() + 1000000009 * ToType.GetHashCode();
}
}
}
#endregion
#region ImplicitConversion #region ImplicitConversion
public Conversion ImplicitConversion(ResolveResult resolveResult, IType toType) public Conversion ImplicitConversion(ResolveResult resolveResult, IType toType)
{ {
@ -273,11 +305,19 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
throw new ArgumentNullException("fromType"); throw new ArgumentNullException("fromType");
if (toType == null) if (toType == null)
throw new ArgumentNullException("toType"); throw new ArgumentNullException("toType");
// C# 4.0 spec: §6.1
Conversion c = StandardImplicitConversion(fromType, toType);
if (c) return c;
return UserDefinedImplicitConversion(fromType, toType); TypePair pair = new TypePair(fromType, toType);
Conversion c;
if (implicitConversionCache.TryGetValue(pair, out c))
return c;
// C# 4.0 spec: §6.1
c = StandardImplicitConversion(fromType, toType);
if (!c) {
c = UserDefinedImplicitConversion(fromType, toType);
}
implicitConversionCache[pair] = c;
return c;
} }
public Conversion StandardImplicitConversion(IType fromType, IType toType) public Conversion StandardImplicitConversion(IType fromType, IType toType)
@ -928,7 +968,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
args[i] = new ResolveResult(parameterType); args[i] = new ResolveResult(parameterType);
} }
} }
var or = rr.PerformOverloadResolution(context, args, allowExpandingParams: false); var or = rr.PerformOverloadResolution(context, args, allowExpandingParams: false, conversions: this);
if (or.FoundApplicableCandidate) if (or.FoundApplicableCandidate)
return Conversion.MethodGroupConversion((IMethod)or.BestCandidate); return Conversion.MethodGroupConversion((IMethod)or.BestCandidate);
else else

6
ICSharpCode.NRefactory/CSharp/Resolver/MethodGroupResolveResult.cs

@ -156,13 +156,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return string.Format("[{0} with {1} method(s)]", GetType().Name, this.Methods.Count()); return string.Format("[{0} with {1} method(s)]", GetType().Name, this.Methods.Count());
} }
public OverloadResolution PerformOverloadResolution(ITypeResolveContext context, ResolveResult[] arguments, string[] argumentNames = null, bool allowExtensionMethods = true, bool allowExpandingParams = true) public OverloadResolution PerformOverloadResolution(ITypeResolveContext context, ResolveResult[] arguments, string[] argumentNames = null, bool allowExtensionMethods = true, bool allowExpandingParams = true, Conversions conversions = null)
{ {
Log.WriteLine("Performing overload resolution for " + this); Log.WriteLine("Performing overload resolution for " + this);
Log.WriteCollection(" Arguments: ", arguments); Log.WriteCollection(" Arguments: ", arguments);
var typeArgumentArray = this.TypeArguments.ToArray(); var typeArgumentArray = this.TypeArguments.ToArray();
OverloadResolution or = new OverloadResolution(context, arguments, argumentNames, typeArgumentArray); OverloadResolution or = new OverloadResolution(context, arguments, argumentNames, typeArgumentArray, conversions);
or.AllowExpandingParams = allowExpandingParams; or.AllowExpandingParams = allowExpandingParams;
or.AddMethodLists(methodLists); or.AddMethodLists(methodLists);
@ -182,7 +182,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
extArgumentNames = new string[argumentNames.Length + 1]; extArgumentNames = new string[argumentNames.Length + 1];
argumentNames.CopyTo(extArgumentNames, 1); argumentNames.CopyTo(extArgumentNames, 1);
} }
var extOr = new OverloadResolution(context, extArguments, extArgumentNames, typeArgumentArray); var extOr = new OverloadResolution(context, extArguments, extArgumentNames, typeArgumentArray, conversions);
extOr.AllowExpandingParams = allowExpandingParams; extOr.AllowExpandingParams = allowExpandingParams;
extOr.IsExtensionMethodInvocation = true; extOr.IsExtensionMethodInvocation = true;

4
ICSharpCode.NRefactory/CSharp/Resolver/OverloadResolution.cs

@ -119,7 +119,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
IType[] explicitlyGivenTypeArguments; IType[] explicitlyGivenTypeArguments;
#region Constructor #region Constructor
public OverloadResolution(ITypeResolveContext context, ResolveResult[] arguments, string[] argumentNames = null, IType[] typeArguments = null) public OverloadResolution(ITypeResolveContext context, ResolveResult[] arguments, string[] argumentNames = null, IType[] typeArguments = null, Conversions conversions = null)
{ {
if (context == null) if (context == null)
throw new ArgumentNullException("context"); throw new ArgumentNullException("context");
@ -137,7 +137,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (typeArguments != null && typeArguments.Length > 0) if (typeArguments != null && typeArguments.Length > 0)
this.explicitlyGivenTypeArguments = typeArguments; this.explicitlyGivenTypeArguments = typeArguments;
this.conversions = new Conversions(context); this.conversions = conversions ?? new Conversions(context);
this.AllowExpandingParams = true; this.AllowExpandingParams = true;
} }
#endregion #endregion

4
ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs

@ -1078,7 +1078,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
var addRR = memberLookup.Lookup(targetResult, "Add", EmptyList<IType>.Instance, true); var addRR = memberLookup.Lookup(targetResult, "Add", EmptyList<IType>.Instance, true);
var mgrr = addRR as MethodGroupResolveResult; var mgrr = addRR as MethodGroupResolveResult;
if (mgrr != null) { if (mgrr != null) {
OverloadResolution or = mgrr.PerformOverloadResolution(resolver.Context, addArguments, null, false, false); OverloadResolution or = mgrr.PerformOverloadResolution(resolver.Context, addArguments, null, false, false, resolver.conversions);
var invocationRR = new InvocationResolveResult(targetResult, or, resolver.Context); var invocationRR = new InvocationResolveResult(targetResult, or, resolver.Context);
StoreResult(aie, invocationRR); StoreResult(aie, invocationRR);
ProcessConversionsInResult(invocationRR); ProcessConversionsInResult(invocationRR);
@ -1923,7 +1923,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
for (int i = 0; i < returnValues.Count; i++) { for (int i = 0; i < returnValues.Count; i++) {
returnValues[i] = resolveResultCache[alv.ReturnExpressions[i]]; returnValues[i] = resolveResultCache[alv.ReturnExpressions[i]];
} }
TypeInference ti = new TypeInference(resolver.Context); TypeInference ti = new TypeInference(resolver.Context, resolver.conversions);
bool tiSuccess; bool tiSuccess;
inferredReturnType = ti.GetBestCommonType(returnValues, out tiSuccess); inferredReturnType = ti.GetBestCommonType(returnValues, out tiSuccess);
// Failure to infer a return type does not make the lambda invalid, // Failure to infer a return type does not make the lambda invalid,

38
ICSharpCode.NRefactory/TypeSystem/ByReferenceType.cs

@ -22,7 +22,7 @@ using ICSharpCode.NRefactory.TypeSystem.Implementation;
namespace ICSharpCode.NRefactory.TypeSystem namespace ICSharpCode.NRefactory.TypeSystem
{ {
[Serializable] [Serializable]
public sealed class ByReferenceType : TypeWithElementType public sealed class ByReferenceType : TypeWithElementType, ISupportsInterning
{ {
public ByReferenceType(IType elementType) : base(elementType) public ByReferenceType(IType elementType) : base(elementType)
{ {
@ -67,12 +67,28 @@ namespace ICSharpCode.NRefactory.TypeSystem
else else
return new ByReferenceType(e); return new ByReferenceType(e);
} }
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
{
elementType = provider.Intern(elementType);
}
int ISupportsInterning.GetHashCodeForInterning()
{
return GetHashCode();
}
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
{
ByReferenceType brt = other as ByReferenceType;
return brt != null && this.elementType == brt.elementType;
}
} }
[Serializable] [Serializable]
public class ByReferenceTypeReference : ITypeReference public class ByReferenceTypeReference : ITypeReference, ISupportsInterning
{ {
readonly ITypeReference elementType; ITypeReference elementType;
public ByReferenceTypeReference(ITypeReference elementType) public ByReferenceTypeReference(ITypeReference elementType)
{ {
@ -102,5 +118,21 @@ namespace ICSharpCode.NRefactory.TypeSystem
else else
return new ByReferenceTypeReference(elementType); return new ByReferenceTypeReference(elementType);
} }
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
{
elementType = provider.Intern(elementType);
}
int ISupportsInterning.GetHashCodeForInterning()
{
return elementType.GetHashCode() ^ 91725814;
}
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
{
ByReferenceTypeReference brt = other as ByReferenceTypeReference;
return brt != null && this.elementType == brt.elementType;
}
} }
} }

1
ICSharpCode.NRefactory/TypeSystem/Implementation/CompoundTypeDefinition.cs

@ -25,6 +25,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
/// <summary> /// <summary>
/// Type definition that represents a partial class with multiple parts. /// Type definition that represents a partial class with multiple parts.
/// </summary> /// </summary>
[Serializable]
public class CompoundTypeDefinition : DefaultTypeDefinition public class CompoundTypeDefinition : DefaultTypeDefinition
{ {
IList<ITypeDefinition> parts; IList<ITypeDefinition> parts;

1
ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultExplicitInterfaceImplementation.cs

@ -23,6 +23,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
/// <summary> /// <summary>
/// Default implementation for IExplicitInterfaceImplementation. /// Default implementation for IExplicitInterfaceImplementation.
/// </summary> /// </summary>
[Serializable]
public sealed class DefaultExplicitInterfaceImplementation : Immutable, IExplicitInterfaceImplementation, ISupportsInterning public sealed class DefaultExplicitInterfaceImplementation : Immutable, IExplicitInterfaceImplementation, ISupportsInterning
{ {
public ITypeReference InterfaceType { get; private set; } public ITypeReference InterfaceType { get; private set; }

38
ICSharpCode.NRefactory/TypeSystem/PointerType.cs

@ -23,7 +23,7 @@ using ICSharpCode.NRefactory.TypeSystem.Implementation;
namespace ICSharpCode.NRefactory.TypeSystem namespace ICSharpCode.NRefactory.TypeSystem
{ {
[Serializable] [Serializable]
public sealed class PointerType : TypeWithElementType public sealed class PointerType : TypeWithElementType, ISupportsInterning
{ {
public PointerType(IType elementType) : base(elementType) public PointerType(IType elementType) : base(elementType)
{ {
@ -68,12 +68,28 @@ namespace ICSharpCode.NRefactory.TypeSystem
else else
return new PointerType(e); return new PointerType(e);
} }
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
{
elementType = provider.Intern(elementType);
}
int ISupportsInterning.GetHashCodeForInterning()
{
return elementType.GetHashCode() ^ 91725811;
}
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
{
PointerType o = other as PointerType;
return o != null && this.elementType == o.elementType;
}
} }
[Serializable] [Serializable]
public class PointerTypeReference : ITypeReference public class PointerTypeReference : ITypeReference, ISupportsInterning
{ {
readonly ITypeReference elementType; ITypeReference elementType;
public PointerTypeReference(ITypeReference elementType) public PointerTypeReference(ITypeReference elementType)
{ {
@ -103,5 +119,21 @@ namespace ICSharpCode.NRefactory.TypeSystem
else else
return new PointerTypeReference(elementType); return new PointerTypeReference(elementType);
} }
void ISupportsInterning.PrepareForInterning(IInterningProvider provider)
{
elementType = provider.Intern(elementType);
}
int ISupportsInterning.GetHashCodeForInterning()
{
return elementType.GetHashCode() ^ 91725812;
}
bool ISupportsInterning.EqualsForInterning(ISupportsInterning other)
{
PointerTypeReference o = other as PointerTypeReference;
return o != null && this.elementType == o.elementType;
}
} }
} }

Loading…
Cancel
Save