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

Optimize metadata reading for extension methods #16168

Merged
merged 8 commits into from
Jun 26, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
42 changes: 29 additions & 13 deletions src/Compiler/AbstractIL/il.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1258,6 +1258,9 @@ let storeILCustomAttrs (attrs: ILAttributes) =
else
ILAttributesStored.Given attrs

let mkILCustomAttrsComputed f =
ILAttributesStored.Reader(fun _ -> f ())

let mkILCustomAttrsReader f = ILAttributesStored.Reader f

type ILCodeLabel = int
Expand Down Expand Up @@ -2611,6 +2614,14 @@ let convertInitSemantics (init: ILTypeInit) =
| ILTypeInit.BeforeField -> TypeAttributes.BeforeFieldInit
| ILTypeInit.OnAny -> enum 0

[<Flags>]
type ILTypeDefAdditionalFlags =
| None = 0
| IsKnownToBeAttribute = 1
/// The type can contain extension methods,
/// or this information may not be available at the time the ILTypeDef is created
| CanContainExtensionMethods = 2

[<NoComparison; NoEquality; StructuredFormatDisplay("{DebugText}")>]
type ILTypeDef
(
Expand All @@ -2626,14 +2637,16 @@ type ILTypeDef
methodImpls: ILMethodImplDefs,
events: ILEventDefs,
properties: ILPropertyDefs,
isKnownToBeAttribute: bool,
additionalFlags: ILTypeDefAdditionalFlags,
securityDeclsStored: ILSecurityDeclsStored,
customAttrsStored: ILAttributesStored,
metadataIndex: int32
) =

let mutable customAttrsStored = customAttrsStored

let hasFlag flag = additionalFlags &&& flag = flag

new(name,
attributes,
layout,
Expand All @@ -2646,7 +2659,7 @@ type ILTypeDef
methodImpls,
events,
properties,
isKnownToBeAttribute,
additionalFlags,
securityDecls,
customAttrs) =
ILTypeDef(
Expand All @@ -2662,9 +2675,9 @@ type ILTypeDef
methodImpls,
events,
properties,
isKnownToBeAttribute,
additionalFlags,
storeILSecurityDecls securityDecls,
storeILCustomAttrs customAttrs,
customAttrs,
NoMetadataIdx
)

Expand Down Expand Up @@ -2694,7 +2707,10 @@ type ILTypeDef

member _.Properties = properties

member _.IsKnownToBeAttribute = isKnownToBeAttribute
member _.IsKnownToBeAttribute = hasFlag ILTypeDefAdditionalFlags.IsKnownToBeAttribute

member _.CanContainExtensionMethods =
hasFlag ILTypeDefAdditionalFlags.CanContainExtensionMethods

member _.CustomAttrsStored = customAttrsStored

Expand All @@ -2714,7 +2730,7 @@ type ILTypeDef
?methodImpls,
?events,
?properties,
?isKnownToBeAttribute,
?newAdditionalFlags,
?customAttrs,
?securityDecls
) =
Expand All @@ -2732,11 +2748,11 @@ type ILTypeDef
methodImpls = defaultArg methodImpls x.MethodImpls,
events = defaultArg events x.Events,
properties = defaultArg properties x.Properties,
isKnownToBeAttribute = defaultArg isKnownToBeAttribute x.IsKnownToBeAttribute,
customAttrs = defaultArg customAttrs x.CustomAttrs
additionalFlags = defaultArg newAdditionalFlags additionalFlags,
customAttrs = defaultArg customAttrs (storeILCustomAttrs x.CustomAttrs)
)

member x.CustomAttrs =
member x.CustomAttrs: ILAttributes =
match customAttrsStored with
| ILAttributesStored.Reader f ->
let res = ILAttributes(f x.MetadataIndex)
Expand Down Expand Up @@ -4220,11 +4236,11 @@ let mkILGenericClass (nm, access, genparams, extends, impl, methods, fields, nes
methods = methods,
fields = fields,
nestedTypes = nestedTypes,
customAttrs = attrs,
customAttrs = storeILCustomAttrs attrs,
methodImpls = emptyILMethodImpls,
properties = props,
events = events,
isKnownToBeAttribute = false,
additionalFlags = ILTypeDefAdditionalFlags.None,
securityDecls = emptyILSecurityDecls
)

Expand All @@ -4244,11 +4260,11 @@ let mkRawDataValueTypeDef (iltyp_ValueType: ILType) (nm, size, pack) =
methods = emptyILMethods,
fields = emptyILFields,
nestedTypes = emptyILTypeDefs,
customAttrs = emptyILCustomAttrs,
customAttrs = emptyILCustomAttrsStored,
methodImpls = emptyILMethodImpls,
properties = emptyILProperties,
events = emptyILEvents,
isKnownToBeAttribute = false,
additionalFlags = ILTypeDefAdditionalFlags.None,
securityDecls = emptyILSecurityDecls
)

Expand Down
20 changes: 15 additions & 5 deletions src/Compiler/AbstractIL/il.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

module rec FSharp.Compiler.AbstractIL.IL

open System
open FSharp.Compiler.IO
open System.Collections.Generic
open System.Reflection
Expand Down Expand Up @@ -1481,6 +1482,12 @@ type ILTypeDefs =
/// Calls to <c>ExistsByName</c> will result in all the ILPreTypeDefs being read.
member internal ExistsByName: string -> bool

[<Flags>]
type ILTypeDefAdditionalFlags =
| None = 0
| IsKnownToBeAttribute = 1
| CanContainExtensionMethods = 2

/// Represents IL Type Definitions.
[<NoComparison; NoEquality>]
type ILTypeDef =
Expand All @@ -1499,7 +1506,7 @@ type ILTypeDef =
methodImpls: ILMethodImplDefs *
events: ILEventDefs *
properties: ILPropertyDefs *
isKnownToBeAttribute: bool *
additionalFlags: ILTypeDefAdditionalFlags *
securityDeclsStored: ILSecurityDeclsStored *
customAttrsStored: ILAttributesStored *
metadataIndex: int32 ->
Expand All @@ -1519,9 +1526,9 @@ type ILTypeDef =
methodImpls: ILMethodImplDefs *
events: ILEventDefs *
properties: ILPropertyDefs *
isKnownToBeAttribute: bool *
additionalFlags: ILTypeDefAdditionalFlags *
securityDecls: ILSecurityDecls *
customAttrs: ILAttributes ->
customAttrs: ILAttributesStored ->
ILTypeDef

member Name: string
Expand Down Expand Up @@ -1556,6 +1563,7 @@ type ILTypeDef =
member HasSecurity: bool
member Encoding: ILDefaultPInvokeEncoding
member IsKnownToBeAttribute: bool
member CanContainExtensionMethods: bool

member internal WithAccess: ILTypeDefAccess -> ILTypeDef
member internal WithNestedAccess: ILMemberAccess -> ILTypeDef
Expand Down Expand Up @@ -1584,8 +1592,8 @@ type ILTypeDef =
?methodImpls: ILMethodImplDefs *
?events: ILEventDefs *
?properties: ILPropertyDefs *
?isKnownToBeAttribute: bool *
?customAttrs: ILAttributes *
?newAdditionalFlags: ILTypeDefAdditionalFlags *
?customAttrs: ILAttributesStored *
?securityDecls: ILSecurityDecls ->
ILTypeDef

Expand Down Expand Up @@ -2212,8 +2220,10 @@ val internal mkILTypeForGlobalFunctions: ILScopeRef -> ILType
val mkILCustomAttrs: ILAttribute list -> ILAttributes
val mkILCustomAttrsFromArray: ILAttribute[] -> ILAttributes
val storeILCustomAttrs: ILAttributes -> ILAttributesStored
val mkILCustomAttrsComputed: (unit -> ILAttribute[]) -> ILAttributesStored
val internal mkILCustomAttrsReader: (int32 -> ILAttribute[]) -> ILAttributesStored
val emptyILCustomAttrs: ILAttributes
val emptyILCustomAttrsStored: ILAttributesStored

val mkILSecurityDecls: ILSecurityDecl list -> ILSecurityDecls
val emptyILSecurityDecls: ILSecurityDecls
Expand Down
2 changes: 1 addition & 1 deletion src/Compiler/AbstractIL/ilmorph.fs
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ let rec tdef_ty2ty_ilmbody2ilmbody_mdefs2mdefs isInKnownSet enc fs (tdef: ILType
methodImpls = mimpls_ty2ty fTyInCtxtR tdef.MethodImpls,
events = edefs_ty2ty fTyInCtxtR tdef.Events,
properties = pdefs_ty2ty fTyInCtxtR tdef.Properties,
customAttrs = cattrs_ty2ty fTyInCtxtR tdef.CustomAttrs
customAttrs = storeILCustomAttrs (cattrs_ty2ty fTyInCtxtR tdef.CustomAttrs)
)

and tdefs_ty2ty_ilmbody2ilmbody_mdefs2mdefs isInKnownSet enc fs tdefs =
Expand Down
92 changes: 76 additions & 16 deletions src/Compiler/AbstractIL/ilread.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2112,9 +2112,64 @@ and typeDefReader ctxtH : ILTypeDefStored =
let layout = typeLayoutOfFlags ctxt mdv flags idx

let hasLayout =
(match layout with
| ILTypeDefLayout.Explicit _ -> true
| _ -> false)
match layout with
| ILTypeDefLayout.Explicit _ -> true
| _ -> false

let containsExtensionMethods =
let mutable containsExtensionMethods = false
let searchedKey = TaggedIndex(hca_TypeDef, idx)

let attributesSearcher =
{ new ISeekReadIndexedRowReader<CustomAttributeRow, CustomAttributeRow, CustomAttributeRow> with
member _.GetRow(i, row) =
seekReadCustomAttributeRow ctxt mdv i &row

member _.GetKey(row) = row
member _.CompareKey(key) = hcaCompare searchedKey key.parentIndex
member _.ConvertRow(row) = row
}

let attrsStartIdx, attrsEndIdx =
seekReadIndexedRowsRange
(ctxt.getNumRows TableNames.CustomAttribute)
(isSorted ctxt TableNames.CustomAttribute)
attributesSearcher

let hasAttributes = attrsStartIdx > 0 && attrsEndIdx >= attrsStartIdx
let mutable attrIdx = attrsStartIdx

while hasAttributes && attrIdx <= attrsEndIdx && not containsExtensionMethods do
let mutable attr = Unchecked.defaultof<_>
attributesSearcher.GetRow(attrIdx, &attr)
let attrCtorIdx = attr.typeIndex.index

let name =
if attr.typeIndex.tag = cat_MethodDef then
let idx = seekMethodDefParent ctxt attrCtorIdx
let _, nameIdx, namespaceIdx, _, _, _ = seekReadTypeDefRow ctxt idx
readBlobHeapAsTypeName ctxt (nameIdx, namespaceIdx)
else
let mrpTag, _, _ = seekReadMemberRefRow ctxt mdv attrCtorIdx

if mrpTag.tag <> mrp_TypeRef then
""
else
let _, nameIdx, namespaceIdx = seekReadTypeRefRow ctxt mdv mrpTag.index
readBlobHeapAsTypeName ctxt (nameIdx, namespaceIdx)

if name = "System.Runtime.CompilerServices.ExtensionAttribute" then
containsExtensionMethods <- true

attrIdx <- attrIdx + 1

containsExtensionMethods

let additionalFlags =
if containsExtensionMethods then
ILTypeDefAdditionalFlags.CanContainExtensionMethods
else
ILTypeDefAdditionalFlags.None

let mdefs = seekReadMethods ctxt numTypars methodsIdx endMethodsIdx
let fdefs = seekReadFields ctxt (numTypars, hasLayout) fieldsIdx endFieldsIdx
Expand All @@ -2138,7 +2193,7 @@ and typeDefReader ctxtH : ILTypeDefStored =
methodImpls = mimpls,
events = events,
properties = props,
isKnownToBeAttribute = false,
additionalFlags = additionalFlags,
customAttrsStored = ctxt.customAttrsReader_TypeDef,
metadataIndex = idx
))
Expand Down Expand Up @@ -2797,22 +2852,27 @@ and seekReadMemberRefAsFieldSpecUncached ctxtH (MemberRefAsFspecIdx(numTypars, i
// method-range and field-range start/finish indexes
and seekReadMethodDefAsMethodData ctxt idx = ctxt.seekReadMethodDefAsMethodData idx

and seekMethodDefParent (ctxt: ILMetadataReader) methodIdx =
seekReadIndexedRow (
ctxt.getNumRows TableNames.TypeDef,
(fun i -> i, seekReadTypeDefRowWithExtents ctxt i),
id,
(fun (_, ((_, _, _, _, _, methodsIdx), (_, endMethodsIdx))) ->
if endMethodsIdx <= methodIdx then
1
elif methodsIdx <= methodIdx && methodIdx < endMethodsIdx then
0
else
-1),
true,
fst
)

and seekReadMethodDefAsMethodDataUncached ctxtH idx =
let (ctxt: ILMetadataReader) = getHole ctxtH
let mdv = ctxt.mdfile.GetView()
// Look for the method def parent.
let tidx =
seekReadIndexedRow (
ctxt.getNumRows TableNames.TypeDef,
(fun i -> i, seekReadTypeDefRowWithExtents ctxt i),
id,
(fun (_, ((_, _, _, _, _, methodsIdx), (_, endMethodsIdx))) ->
if endMethodsIdx <= idx then 1
elif methodsIdx <= idx && idx < endMethodsIdx then 0
else -1),
true,
fst
)
let tidx = seekMethodDefParent ctxt idx
// Create a formal instantiation if needed
let typeGenericArgs = seekReadGenericParams ctxt 0 (tomd_TypeDef, tidx)
let typeGenericArgsCount = typeGenericArgs.Length
Expand Down
5 changes: 4 additions & 1 deletion src/Compiler/Checking/NameResolution.fs
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,10 @@ let NextExtensionMethodPriority() = uint64 (newStamp())
/// Checks if the type is used for C# style extension members.
let IsTyconRefUsedForCSharpStyleExtensionMembers g m (tcref: TyconRef) =
// Type must be non-generic and have 'Extension' attribute
isNil(tcref.Typars m) && TyconRefHasAttribute g m g.attrib_ExtensionAttribute tcref
match metadataOfTycon tcref.Deref with
| ILTypeMetadata(TILObjectReprData(_, _, tdef)) -> tdef.CanContainExtensionMethods
| _ -> true
&& isNil(tcref.Typars m) && TyconRefHasAttribute g m g.attrib_ExtensionAttribute tcref

/// Checks if the type is used for C# style extension members.
let IsTypeUsedForCSharpStyleExtensionMembers g m ty =
Expand Down
8 changes: 4 additions & 4 deletions src/Compiler/CodeGen/EraseClosures.fs
Original file line number Diff line number Diff line change
Expand Up @@ -578,11 +578,11 @@ let rec convIlxClosureDef cenv encl (td: ILTypeDef) clo =
extends = Some cenv.mkILTyFuncTy,
methods = mkILMethods (ctorMethodDef :: nowApplyMethDef :: nowMethods),
fields = mkILFields (mkILCloFldDefs cenv nowFields @ td.Fields.AsList()),
customAttrs = emptyILCustomAttrs,
customAttrs = emptyILCustomAttrsStored,
methodImpls = emptyILMethodImpls,
properties = emptyILProperties,
events = emptyILEvents,
isKnownToBeAttribute = false,
additionalFlags = ILTypeDefAdditionalFlags.None,
securityDecls = emptyILSecurityDecls
)
.WithSpecialName(false)
Expand Down Expand Up @@ -712,11 +712,11 @@ let rec convIlxClosureDef cenv encl (td: ILTypeDef) clo =
extends = Some nowEnvParentClass,
methods = mkILMethods (ctorMethodDef :: nowApplyMethDef :: nowMethods),
fields = mkILFields (mkILCloFldDefs cenv nowFields @ td.Fields.AsList()),
customAttrs = emptyILCustomAttrs,
customAttrs = emptyILCustomAttrsStored,
methodImpls = emptyILMethodImpls,
properties = emptyILProperties,
events = emptyILEvents,
isKnownToBeAttribute = false,
additionalFlags = ILTypeDefAdditionalFlags.None,
securityDecls = emptyILSecurityDecls
)
.WithHasSecurity(false)
Expand Down
4 changes: 2 additions & 2 deletions src/Compiler/CodeGen/EraseUnions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1452,8 +1452,8 @@ let mkClassUnionDef
methodImpls = emptyILMethodImpls,
events = emptyILEvents,
properties = emptyILProperties,
isKnownToBeAttribute = false,
customAttrs = emptyILCustomAttrs
additionalFlags = ILTypeDefAdditionalFlags.None,
customAttrs = emptyILCustomAttrsStored
)
.WithNestedAccess(cud.UnionCasesAccessibility)
.WithAbstract(true)
Expand Down
Loading
Loading