Skip to content

Commit

Permalink
Optimize IsKnownType/IsKnownAttribute (see #1204 and #2594)
Browse files Browse the repository at this point in the history
  • Loading branch information
siegfriedpammer committed Jan 28, 2022
1 parent 2ee248b commit 6533f75
Showing 1 changed file with 122 additions and 4 deletions.
126 changes: 122 additions & 4 deletions ICSharpCode.Decompiler/SRMExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -195,15 +195,133 @@ public static FullTypeName GetFullTypeName(this EntityHandle handle, MetadataRea
public static bool IsKnownType(this EntityHandle handle, MetadataReader reader,
KnownTypeCode knownType)
{
return !handle.IsNil
&& GetFullTypeName(handle, reader) == KnownTypeReference.Get(knownType).TypeName;
return IsKnownType(handle, reader, KnownTypeReference.Get(knownType).TypeName);
}

internal static bool IsKnownType(this EntityHandle handle, MetadataReader reader,
KnownAttribute knownType)
{
return !handle.IsNil
&& GetFullTypeName(handle, reader) == knownType.GetTypeName();
return IsKnownType(handle, reader, knownType.GetTypeName());
}

private static bool IsKnownType(EntityHandle handle, MetadataReader reader, TopLevelTypeName knownType)
{
if (handle.IsNil)
return false;
StringHandle nameHandle, namespaceHandle;
switch (handle.Kind)
{
case HandleKind.TypeReference:
var tr = reader.GetTypeReference((TypeReferenceHandle)handle);
// ignore exported and nested types
if (tr.ResolutionScope.IsNil || tr.ResolutionScope.Kind == HandleKind.TypeReference)
return false;
nameHandle = tr.Name;
namespaceHandle = tr.Namespace;
break;
case HandleKind.TypeDefinition:
var td = reader.GetTypeDefinition((TypeDefinitionHandle)handle);
if (td.IsNested)
return false;
nameHandle = td.Name;
namespaceHandle = td.Namespace;
break;
case HandleKind.TypeSpecification:
var ts = reader.GetTypeSpecification((TypeSpecificationHandle)handle);
var blob = reader.GetBlobReader(ts.Signature);
return SignatureIsKnownType(reader, knownType, ref blob);
default:
return false;
}
if (knownType.TypeParameterCount == 0)
{
if (!reader.StringComparer.Equals(nameHandle, knownType.Name))
return false;
}
else
{
string name = reader.GetString(nameHandle);
name = ReflectionHelper.SplitTypeParameterCountFromReflectionName(name, out int typeParameterCount);
if (typeParameterCount != knownType.TypeParameterCount || name != knownType.Name)
return false;
}
if (namespaceHandle.IsNil)
{
return knownType.Namespace.Length == 0;
}
else
{
return reader.StringComparer.Equals(namespaceHandle, knownType.Namespace);
}
}

private static bool SignatureIsKnownType(MetadataReader reader, TopLevelTypeName knownType, ref BlobReader blob)
{
if (!blob.TryReadCompressedInteger(out int typeCode))
return false;
switch (typeCode)
{
case 0x1: // ELEMENT_TYPE_VOID
return knownType.IsKnownType(KnownTypeCode.Void);
case 0x2: // ELEMENT_TYPE_BOOLEAN
return knownType.IsKnownType(KnownTypeCode.Boolean);
case 0x3: // ELEMENT_TYPE_CHAR
return knownType.IsKnownType(KnownTypeCode.Char);
case 0x4: // ELEMENT_TYPE_I1
return knownType.IsKnownType(KnownTypeCode.SByte);
case 0x5: // ELEMENT_TYPE_U1
return knownType.IsKnownType(KnownTypeCode.Byte);
case 0x6: // ELEMENT_TYPE_I2
return knownType.IsKnownType(KnownTypeCode.Int16);
case 0x7: // ELEMENT_TYPE_U2
return knownType.IsKnownType(KnownTypeCode.UInt16);
case 0x8: // ELEMENT_TYPE_I4
return knownType.IsKnownType(KnownTypeCode.Int32);
case 0x9: // ELEMENT_TYPE_U4
return knownType.IsKnownType(KnownTypeCode.UInt32);
case 0xA: // ELEMENT_TYPE_I8
return knownType.IsKnownType(KnownTypeCode.Int64);
case 0xB: // ELEMENT_TYPE_U8
return knownType.IsKnownType(KnownTypeCode.UInt64);
case 0xC: // ELEMENT_TYPE_R4
return knownType.IsKnownType(KnownTypeCode.Single);
case 0xD: // ELEMENT_TYPE_R8
return knownType.IsKnownType(KnownTypeCode.Double);
case 0xE: // ELEMENT_TYPE_STRING
return knownType.IsKnownType(KnownTypeCode.String);
case 0x16: // ELEMENT_TYPE_TYPEDBYREF
return knownType.IsKnownType(KnownTypeCode.TypedReference);
case 0x18: // ELEMENT_TYPE_I
return knownType.IsKnownType(KnownTypeCode.IntPtr);
case 0x19: // ELEMENT_TYPE_U
return knownType.IsKnownType(KnownTypeCode.UIntPtr);
case 0x1C: // ELEMENT_TYPE_OBJECT
return knownType.IsKnownType(KnownTypeCode.Object);
case 0xF: // ELEMENT_TYPE_PTR
case 0x10: // ELEMENT_TYPE_BYREF
case 0x45: // ELEMENT_TYPE_PINNED
case 0x1D: // ELEMENT_TYPE_SZARRAY
case 0x1B: // ELEMENT_TYPE_FNPTR
case 0x14: // ELEMENT_TYPE_ARRAY
return false;
case 0x1F: // ELEMENT_TYPE_CMOD_REQD
case 0x20: // ELEMENT_TYPE_CMOD_OPT
// modifier
blob.ReadTypeHandle(); // skip modifier
return SignatureIsKnownType(reader, knownType, ref blob);
case 0x15: // ELEMENT_TYPE_GENERICINST
// generic type
return SignatureIsKnownType(reader, knownType, ref blob);
case 0x13: // ELEMENT_TYPE_VAR
case 0x1E: // ELEMENT_TYPE_MVAR
// index
return false;
case 0x11: // ELEMENT_TYPE_VALUETYPE
case 0x12: // ELEMENT_TYPE_CLASS
return IsKnownType(blob.ReadTypeHandle(), reader, knownType);
default:
return false;
}
}

public static FullTypeName GetFullTypeName(this TypeSpecificationHandle handle, MetadataReader reader)
Expand Down

0 comments on commit 6533f75

Please sign in to comment.