Skip to content

Commit 0328c7e

Browse files
perf/refactor: convert ILFieldDefs/ILEventDefs/ILPropertyDefs to concrete classes with lazy name-lookup dictionaries; add Dependabot config
- Convert ILFieldDefs, ILEventDefs, ILPropertyDefs from abstract interface types to concrete classes (mirroring the existing ILMethodDefs pattern). Each class holds a Lazy<T[]> and builds a lazy Dictionary<string, T> for O(1) TryFindByName lookups. - Update all instantiation sites (empty instances, seekReadFields, seekReadEvents, seekReadProperties, binary writer) to use the new constructors. - Add TryFindByName callers in TypeSymbol.GetField/GetPropertyImpl/GetEvent and TargetTypeDefinition.GetEnumUnderlyingType to replace O(n) Array.tryFind scans. - Add lazy fieldDefsMap/propDefsMap/eventDefsMap in TargetTypeDefinition for O(1) single-member lookup in GetField/GetPropertyImpl/GetEvent. - Lazy evaluation of Entries also means repeated .Entries accesses on seekRead-produced ILFieldDefs/ILEventDefs/ILPropertyDefs no longer re-read the underlying metadata on each call. - Also: add .github/dependabot.yml for weekly GitHub Actions updates. - Fix typo: 'occured' -> 'occurred' in error message. 126/126 tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 2571b7d commit 0328c7e

2 files changed

Lines changed: 82 additions & 35 deletions

File tree

.github/dependabot.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "github-actions"
4+
directory: "/"
5+
schedule:
6+
interval: "weekly"
7+
day: "monday"
8+
labels:
9+
- "enhancement"

src/ProvidedTypes.fs

Lines changed: 73 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2920,8 +2920,16 @@ module internal AssemblyReader =
29202920
member x.IsRTSpecialName = (x.Attributes &&& EventAttributes.RTSpecialName) <> enum<_>(0)
29212921
override x.ToString() = "event " + x.Name
29222922

2923-
type ILEventDefs =
2924-
abstract Entries: ILEventDef[]
2923+
type ILEventDefs(larr: Lazy<ILEventDef[]>) =
2924+
let lmap = lazy (
2925+
let d = Dictionary<string, ILEventDef>()
2926+
for ev in larr.Force() do d.[ev.Name] <- ev
2927+
d)
2928+
member __.Entries = larr.Force()
2929+
member __.TryFindByName nm =
2930+
match lmap.Value.TryGetValue(nm) with
2931+
| true, ev -> Some ev
2932+
| _ -> None
29252933

29262934
[<NoComparison; NoEquality>]
29272935
type ILPropertyDef =
@@ -2947,8 +2955,16 @@ module internal AssemblyReader =
29472955
member x.IsRTSpecialName = x.Attributes &&& PropertyAttributes.RTSpecialName <> enum 0
29482956
override x.ToString() = "property " + x.Name
29492957

2950-
type ILPropertyDefs =
2951-
abstract Entries: ILPropertyDef[]
2958+
type ILPropertyDefs(larr: Lazy<ILPropertyDef[]>) =
2959+
let lmap = lazy (
2960+
let d = Dictionary<string, ILPropertyDef>()
2961+
for p in larr.Force() do d.[p.Name] <- p
2962+
d)
2963+
member __.Entries = larr.Force()
2964+
member __.TryFindByName nm =
2965+
match lmap.Value.TryGetValue(nm) with
2966+
| true, p -> Some p
2967+
| _ -> None
29522968

29532969
[<NoComparison; NoEquality>]
29542970
type ILFieldDef =
@@ -2980,8 +2996,16 @@ module internal AssemblyReader =
29802996
override x.ToString() = "field " + x.Name
29812997

29822998

2983-
type ILFieldDefs =
2984-
abstract Entries: ILFieldDef[]
2999+
type ILFieldDefs(larr: Lazy<ILFieldDef[]>) =
3000+
let lmap = lazy (
3001+
let d = Dictionary<string, ILFieldDef>()
3002+
for f in larr.Force() do d.[f.Name] <- f
3003+
d)
3004+
member __.Entries = larr.Force()
3005+
member __.TryFindByName nm =
3006+
match lmap.Value.TryGetValue(nm) with
3007+
| true, f -> Some f
3008+
| _ -> None
29853009

29863010
type ILMethodImplDef =
29873011
{ Overrides: ILOverridesSpec
@@ -4692,14 +4716,14 @@ module internal AssemblyReader =
46924716
let td = ltd.Force()
46934717
(td.Name, ltd)
46944718

4695-
let emptyILEvents = { new ILEventDefs with member __.Entries = [| |] }
4696-
let emptyILProperties = { new ILPropertyDefs with member __.Entries = [| |] }
4719+
let emptyILEvents = ILEventDefs(lazy [| |])
4720+
let emptyILProperties = ILPropertyDefs(lazy [| |])
46974721
let emptyILTypeDefs = ILTypeDefs (lazy [| |])
46984722
let emptyILCustomAttrs = { new ILCustomAttrs with member __.Entries = [| |] }
46994723
let mkILCustomAttrs x = { new ILCustomAttrs with member __.Entries = x }
47004724
let emptyILMethodImpls = { new ILMethodImplDefs with member __.Entries = [| |] }
47014725
let emptyILMethods = ILMethodDefs (lazy [| |])
4702-
let emptyILFields = { new ILFieldDefs with member __.Entries = [| |] }
4726+
let emptyILFields = ILFieldDefs(lazy [| |])
47034727

47044728
let mkILTy boxed tspec =
47054729
match boxed with
@@ -5771,10 +5795,7 @@ module internal AssemblyReader =
57715795
Token = idx }
57725796

57735797
and seekReadFields (numtypars, hasLayout) fidx1 fidx2 =
5774-
{ new ILFieldDefs with
5775-
member __.Entries =
5776-
[| for i = fidx1 to fidx2 - 1 do
5777-
yield seekReadField (numtypars, hasLayout) i |] }
5798+
ILFieldDefs(lazy [| for i = fidx1 to fidx2 - 1 do yield seekReadField (numtypars, hasLayout) i |])
57785799

57795800
and seekReadMethods numtypars midx1 midx2 =
57805801
ILMethodDefs
@@ -6100,9 +6121,9 @@ module internal AssemblyReader =
61006121
Token = idx}
61016122

61026123
and seekReadEvents numtypars tidx =
6103-
{ new ILEventDefs with
6104-
member __.Entries =
6105-
match seekReadOptionalIndexedRow (getNumRows ILTableNames.EventMap, (fun i -> i, seekReadEventMapRow i), (fun (_, row) -> fst row), compare tidx, false, (fun (i, row) -> (i, snd row))) with
6124+
ILEventDefs
6125+
(lazy
6126+
(match seekReadOptionalIndexedRow (getNumRows ILTableNames.EventMap, (fun i -> i, seekReadEventMapRow i), (fun (_, row) -> fst row), compare tidx, false, (fun (i, row) -> (i, snd row))) with
61066127
| None -> [| |]
61076128
| Some (rowNum, beginEventIdx) ->
61086129
let endEventIdx =
@@ -6111,9 +6132,8 @@ module internal AssemblyReader =
61116132
else
61126133
let (_, endEventIdx) = seekReadEventMapRow (rowNum + 1)
61136134
endEventIdx
6114-
61156135
[| for i in beginEventIdx .. endEventIdx - 1 do
6116-
yield seekReadEvent numtypars i |] }
6136+
yield seekReadEvent numtypars i |]))
61176137

61186138
and seekReadProperty numtypars idx =
61196139
let (flags, nameIdx, typIdx) = seekReadPropertyRow idx
@@ -6139,9 +6159,9 @@ module internal AssemblyReader =
61396159
Token = idx }
61406160

61416161
and seekReadProperties numtypars tidx =
6142-
{ new ILPropertyDefs with
6143-
member __.Entries =
6144-
match seekReadOptionalIndexedRow (getNumRows ILTableNames.PropertyMap, (fun i -> i, seekReadPropertyMapRow i), (fun (_, row) -> fst row), compare tidx, false, (fun (i, row) -> (i, snd row))) with
6162+
ILPropertyDefs
6163+
(lazy
6164+
(match seekReadOptionalIndexedRow (getNumRows ILTableNames.PropertyMap, (fun i -> i, seekReadPropertyMapRow i), (fun (_, row) -> fst row), compare tidx, false, (fun (i, row) -> (i, snd row))) with
61456165
| None -> [| |]
61466166
| Some (rowNum, beginPropIdx) ->
61476167
let endPropIdx =
@@ -6151,7 +6171,7 @@ module internal AssemblyReader =
61516171
let (_, endPropIdx) = seekReadPropertyMapRow (rowNum + 1)
61526172
endPropIdx
61536173
[| for i in beginPropIdx .. endPropIdx - 1 do
6154-
yield seekReadProperty numtypars i |] }
6174+
yield seekReadProperty numtypars i |]))
61556175

61566176

61576177
and seekReadCustomAttrs idx =
@@ -7514,7 +7534,7 @@ namespace ProviderImplementation.ProvidedTypes
75147534
override this.GetField(name, bindingFlags) =
75157535
match kind with
75167536
| TypeSymbolKind.TargetGeneric gtd ->
7517-
gtd.Metadata.Fields.Entries |> Array.tryFind (fun md -> md.Name = name)
7537+
gtd.Metadata.Fields.TryFindByName name
75187538
|> Option.map (gtd.MakeFieldInfo this)
75197539
|> Option.toObj
75207540
| TypeSymbolKind.OtherGeneric gtd ->
@@ -7528,8 +7548,7 @@ namespace ProviderImplementation.ProvidedTypes
75287548
override this.GetPropertyImpl(name, bindingFlags, _binder, _returnType, _types, _modifiers) =
75297549
match kind with
75307550
| TypeSymbolKind.TargetGeneric gtd ->
7531-
gtd.Metadata.Properties.Entries
7532-
|> Array.tryFind (fun md -> md.Name = name)
7551+
gtd.Metadata.Properties.TryFindByName name
75337552
|> Option.map (gtd.MakePropertyInfo this)
75347553
|> Option.toObj
75357554
| TypeSymbolKind.OtherGeneric gtd ->
@@ -7543,8 +7562,7 @@ namespace ProviderImplementation.ProvidedTypes
75437562
override this.GetEvent(name, bindingFlags) =
75447563
match kind with
75457564
| TypeSymbolKind.TargetGeneric gtd ->
7546-
gtd.Metadata.Events.Entries
7547-
|> Array.tryFind (fun md -> md.Name = name)
7565+
gtd.Metadata.Events.TryFindByName name
75487566
|> Option.map (gtd.MakeEventInfo this)
75497567
|> Option.toObj
75507568
| TypeSymbolKind.OtherGeneric gtd ->
@@ -7994,6 +8012,20 @@ namespace ProviderImplementation.ProvidedTypes
79948012
let propDefs = lazy (inp.Properties.Entries |> Array.map (txILPropertyDef this))
79958013
let nestedDefs = lazy (inp.NestedTypes.Entries |> Array.map (asm.TxILTypeDef (Some (this :> Type))))
79968014

8015+
// Lazy dictionaries for O(1) single-member lookup by name.
8016+
let fieldDefsMap =
8017+
lazy (let d = Dictionary<string, FieldInfo>()
8018+
for f in fieldDefs.Force() do d.[f.Name] <- f
8019+
d)
8020+
let propDefsMap =
8021+
lazy (let d = Dictionary<string, PropertyInfo>()
8022+
for p in propDefs.Force() do d.[p.Name] <- p
8023+
d)
8024+
let eventDefsMap =
8025+
lazy (let d = Dictionary<string, EventInfo>()
8026+
for e in eventDefs.Force() do d.[e.Name] <- e
8027+
d)
8028+
79978029
// Cache derived properties that are computed from immutable input data.
79988030
// The F# compiler may call FullName, BaseType and GetInterfaces() many times per type
79998031
// during type-checking; caching avoids repeated string allocations and type-resolution work.
@@ -8063,13 +8095,19 @@ namespace ProviderImplementation.ProvidedTypes
80638095
md |> Option.map (txILMethodDef this) |> Option.toObj
80648096

80658097
override this.GetField(name, _bindingFlags) =
8066-
fieldDefs.Force() |> Array.tryFind (fun f -> f.Name = name) |> Option.toObj
8098+
match fieldDefsMap.Value.TryGetValue(name) with
8099+
| true, f -> f
8100+
| _ -> null
80678101

80688102
override this.GetPropertyImpl(name, _bindingFlags, _binder, _returnType, _types, _modifiers) =
8069-
propDefs.Force() |> Array.tryFind (fun p -> p.Name = name) |> Option.toObj
8103+
match propDefsMap.Value.TryGetValue(name) with
8104+
| true, p -> p
8105+
| _ -> null
80708106

80718107
override this.GetEvent(name, _bindingFlags) =
8072-
eventDefs.Force() |> Array.tryFind (fun ev -> ev.Name = name) |> Option.toObj
8108+
match eventDefsMap.Value.TryGetValue(name) with
8109+
| true, ev -> ev
8110+
| _ -> null
80738111

80748112
override this.GetNestedType(name, _bindingFlags) =
80758113
inp.NestedTypes.TryFindByName(UNone, name) |> Option.map (asm.TxILTypeDef (Some (this :> Type))) |> Option.toObj
@@ -8107,7 +8145,7 @@ namespace ProviderImplementation.ProvidedTypes
81078145
if this.IsEnum then
81088146
// Read the underlying type from the special "value__" field that the compiler emits for every enum.
81098147
// This correctly handles non-Int32 backing types (byte, int16, int64, etc.).
8110-
let valueField = inp.Fields.Entries |> Array.tryFind (fun f -> f.Name = "value__")
8148+
let valueField = inp.Fields.TryFindByName "value__"
81118149
match valueField with
81128150
| Some f -> txILType ([| |], [| |]) f.FieldType
81138151
| None -> txILType ([| |], [| |]) ilGlobals.typ_Int32
@@ -9285,7 +9323,7 @@ namespace ProviderImplementation.ProvidedTypes
92859323
if i < 0 then
92869324
let msg =
92879325
if toTgt then sprintf "The design-time type '%O' utilized by a type provider was not found in the target reference assembly set '%A'. You may be referencing a profile which contains fewer types than those needed by the type provider you are using." t (getTargetAssemblies() |> Seq.toList)
9288-
elif getSourceAssemblies() |> Seq.isEmpty then sprintf "A failure occured while determining compilation references"
9326+
elif getSourceAssemblies() |> Seq.isEmpty then sprintf "A failure occurred while determining compilation references"
92899327
else sprintf "The target type '%O' utilized by a type provider was not found in the design-time assembly set '%A'. Please report this problem to the project site for the type provider." t (getSourceAssemblies() |> Seq.toList)
92909328
failwith msg
92919329
else
@@ -14111,9 +14149,9 @@ namespace ProviderImplementation.ProvidedTypes
1411114149
//SecurityDecls=emptyILSecurityDecls;
1411214150
//HasSecurity=false;
1411314151
NestedTypes = ILTypeDefs( lazy [| for x in nestedTypes -> let td = x.Content in td.Namespace, td.Name, lazy td |] )
14114-
Fields = { new ILFieldDefs with member __.Entries = [| for x in fields -> x.Content |] }
14115-
Properties = { new ILPropertyDefs with member __.Entries = [| for x in props -> x.Content |] }
14116-
Events = { new ILEventDefs with member __.Entries = [| for x in events -> x.Content |] }
14152+
Fields = ILFieldDefs(lazy [| for x in fields -> x.Content |])
14153+
Properties = ILPropertyDefs(lazy [| for x in props -> x.Content |])
14154+
Events = ILEventDefs(lazy [| for x in events -> x.Content |])
1411714155
Methods = ILMethodDefs (lazy [| for x in methods -> x.Content |])
1411814156
MethodImpls = { new ILMethodImplDefs with member __.Entries = methodImpls.ToArray() }
1411914157
CustomAttrs = mkILCustomAttrs (cattrs.ToArray())

0 commit comments

Comments
 (0)