Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Further optimize FindValidCloneMethod #48949

Merged
merged 4 commits into from
Nov 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ internal override MethodSymbol Constructor
}

internal override bool IsRecord => false;
internal override bool HasPossibleWellKnownCloneMethod() => false;

internal override ImmutableArray<NamedTypeSymbol> InterfacesNoUseSiteDiagnostics(ConsList<TypeSymbol> basesBeingResolved)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,5 +142,6 @@ internal override IEnumerable<FieldSymbol> GetFieldsToEmit()
IMethodSymbolInternal ISynthesizedMethodBodyImplementationSymbol.Method => _topLevelMethod;

internal override bool IsRecord => false;
internal override bool HasPossibleWellKnownCloneMethod() => false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,6 @@ internal override ImmutableArray<NamedTypeSymbol> InterfacesNoUseSiteDiagnostics
internal override NamedTypeSymbol BaseTypeNoUseSiteDiagnostics => ContainingAssembly.GetSpecialType(SpecialType.System_Object);

internal override bool IsRecord => false;
internal override bool HasPossibleWellKnownCloneMethod() => false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public sealed override bool AreLocalsZeroed
}

internal override bool IsRecord => false;
internal override bool HasPossibleWellKnownCloneMethod() => false;

bool ISynthesizedMethodBodyImplementationSymbol.HasMethodBodyDependency
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,8 @@ public override int GetHashCode()
{
return this.TypeDescriptor.GetHashCode();
}

internal override bool HasPossibleWellKnownCloneMethod() => false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,8 @@ private SynthesizedAttributeData TrySynthesizeDebuggerDisplayAttribute()
WellKnownMember.System_Diagnostics_DebuggerDisplayAttribute__Type,
new TypedConstant(Manager.System_String, TypedConstantKind.Primitive, "<Anonymous Type>"))));
}

internal override bool HasPossibleWellKnownCloneMethod() => false;
}
}
}
3 changes: 2 additions & 1 deletion src/Compilers/CSharp/Portable/Symbols/ErrorTypeSymbol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,8 @@ protected sealed override ITypeSymbol CreateITypeSymbol(CodeAnalysis.NullableAnn
return new PublicModel.ErrorTypeSymbol(this, nullableAnnotation);
}

internal override bool IsRecord => false;
internal sealed override bool IsRecord => false;
internal sealed override bool HasPossibleWellKnownCloneMethod() => false;
}

internal abstract class SubstitutedErrorTypeSymbol : ErrorTypeSymbol
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -560,16 +560,6 @@ internal override bool IsRecord
{
get
{
// First, do a check to see if there are even any members named <Clone>$. If we have to actually find the clone
// method, it can be expensive, because we have to load all the members. MemberNames just loads the strings, which
// is much cheaper.
if (!MemberNames.Contains(WellKnownMemberNames.CloneMethodName))
{
return false;
}

// There exists a member named <Clone>$. We still need to check to see if it's actually a valid clone method, but
// there's no getting around that now.
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
return SynthesizedRecordClone.FindValidCloneMethod(this, ref useSiteDiagnostics) != null;
}
Expand Down Expand Up @@ -1429,6 +1419,9 @@ public override ImmutableArray<Symbol> GetMembers(string name)
return m;
}

internal sealed override bool HasPossibleWellKnownCloneMethod()
=> MemberNames.Contains(WellKnownMemberNames.CloneMethodName);

internal override FieldSymbol FixedElementField
{
get
Expand Down
7 changes: 7 additions & 0 deletions src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,13 @@ internal abstract bool MangleName
/// no members with this name, returns an empty ImmutableArray. Never returns null.</returns>
public abstract override ImmutableArray<Symbol> GetMembers(string name);

/// <summary>
/// A lightweight check for whether this type has a possible clone method. This is less costly than GetMembers,
/// particularly for PE symbols, and can be used as a cheap heuristic for whether to fully search through all
/// members of this type for a valid clone method.
/// </summary>
internal abstract bool HasPossibleWellKnownCloneMethod();

internal virtual ImmutableArray<Symbol> GetSimpleNonTypeMembers(string name)
{
return GetMembers(name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,8 @@ ImmutableArray<Symbol> makeMembers(ImmutableArray<Symbol> underlyingMembers)

internal sealed override NamedTypeSymbol NativeIntegerUnderlyingType => _underlyingType;

internal override bool IsRecord => false;
internal sealed override bool IsRecord => false;
internal sealed override bool HasPossibleWellKnownCloneMethod() => false;

internal override bool Equals(TypeSymbol? other, TypeCompareKind comparison, IReadOnlyDictionary<TypeParameterSymbol, bool>? isValueTypeOverrideOpt = null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@ public sealed override bool AreLocalsZeroed

internal sealed override NamedTypeSymbol NativeIntegerUnderlyingType => null;

internal override bool IsRecord => _underlyingType.IsRecord;
internal sealed override bool IsRecord => _underlyingType.IsRecord;
internal sealed override bool HasPossibleWellKnownCloneMethod() => _underlyingType.HasPossibleWellKnownCloneMethod();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -240,5 +240,6 @@ public sealed override bool AreLocalsZeroed
=> throw ExceptionUtilities.Unreachable;

internal override bool IsRecord => false;
internal override bool HasPossibleWellKnownCloneMethod() => false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1249,6 +1249,14 @@ public sealed override ImmutableArray<Symbol> GetMembers(string name)
return ImmutableArray<Symbol>.Empty;
}

/// <remarks>
/// For source symbols, there can only be a valid clone method if this is a record, which is a
/// simple syntax check. This will need to change when we generalize cloning, but it's a good
/// heuristic for now.
/// </remarks>
internal override bool HasPossibleWellKnownCloneMethod()
=> IsRecord;

internal override ImmutableArray<Symbol> GetSimpleNonTypeMembers(string name)
{
if (_lazyMembersDictionary != null || declaration.MemberNames.Contains(name))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,7 @@ internal override IEnumerable<CSharpAttributeData> GetCustomAttributesToEmit(PEM

internal sealed override NamedTypeSymbol NativeIntegerUnderlyingType => null;

internal override bool IsRecord => _underlyingType.IsRecord;
internal sealed override bool IsRecord => _underlyingType.IsRecord;
internal sealed override bool HasPossibleWellKnownCloneMethod() => _underlyingType.HasPossibleWellKnownCloneMethod();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,15 @@ internal override void GenerateMethodBody(TypeCompilationState compilationState,

internal static MethodSymbol? FindValidCloneMethod(TypeSymbol containingType, ref HashSet<DiagnosticInfo>? useSiteDiagnostics)
{
if (containingType.IsObjectType())
if (containingType.IsObjectType() || containingType is not NamedTypeSymbol containingNamedType)
{
return null;
}

// If this symbol is from metadata, getting all members can cause us to realize a lot of structures that we otherwise
// don't have to. Optimize for the common case here of there not being a method named <Clone>$. If there is a method
// with that name, it's most likely the one we're interested in, and we can't get around loading everything to find it.
if (!containingNamedType.HasPossibleWellKnownCloneMethod())
{
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ public sealed override bool AreLocalsZeroed
}

internal override bool IsRecord => false;
internal override bool HasPossibleWellKnownCloneMethod() => false;

private sealed class DelegateConstructor : SynthesizedInstanceConstructor
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ public SynthesizedEmbeddedAttributeSymbol(
public override ImmutableArray<MethodSymbol> Constructors => _constructors;

internal override bool IsRecord => false;
internal override bool HasPossibleWellKnownCloneMethod() => false;
}

internal sealed class SynthesizedEmbeddedAttributeConstructorSymbol : SynthesizedInstanceConstructor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public SynthesizedEmbeddedNativeIntegerAttributeSymbol(
public override ImmutableArray<MethodSymbol> Constructors => _constructors;

internal override bool IsRecord => false;
internal override bool HasPossibleWellKnownCloneMethod() => false;

internal override AttributeUsageInfo GetAttributeUsageInfo()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ public SynthesizedEmbeddedNullableAttributeSymbol(
public override ImmutableArray<MethodSymbol> Constructors => _constructors;

internal override bool IsRecord => false;
internal override bool HasPossibleWellKnownCloneMethod() => false;

internal override AttributeUsageInfo GetAttributeUsageInfo()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public SynthesizedEmbeddedNullableContextAttributeSymbol(
public override ImmutableArray<MethodSymbol> Constructors => _constructors;

internal override bool IsRecord => false;
internal override bool HasPossibleWellKnownCloneMethod() => false;

internal override AttributeUsageInfo GetAttributeUsageInfo()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public SynthesizedEmbeddedNullablePublicOnlyAttributeSymbol(
public override ImmutableArray<MethodSymbol> Constructors => _constructors;

internal override bool IsRecord => false;
internal override bool HasPossibleWellKnownCloneMethod() => false;

internal override AttributeUsageInfo GetAttributeUsageInfo()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -325,5 +325,6 @@ internal override AttributeUsageInfo GetAttributeUsageInfo()
internal sealed override NamedTypeSymbol NativeIntegerUnderlyingType => null;

internal override bool IsRecord => false;
internal override bool HasPossibleWellKnownCloneMethod() => false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,7 @@ internal override bool IsInterface
internal sealed override NamedTypeSymbol NativeIntegerUnderlyingType => null;

internal override bool IsRecord => false;
internal override bool HasPossibleWellKnownCloneMethod() => false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How are records represented in the EE? This line caught me a bit off guard. Must be I don't have the full pictuer here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how records are represented in EE, but this doesn't particularly change whatever it is. @tmat, does EE have records support? If so, we likely need to file a separate bug and make a change here.`


[Conditional("DEBUG")]
internal static void VerifyTypeParameters(Symbol container, ImmutableArray<TypeParameterSymbol> typeParameters)
Expand Down