Skip to content

Commit 5ee5e58

Browse files
authored
IL: make ILTypeDefs, ILMethodDefs thread-safe (#16147)
* IL: make ILTypeDefs, ILMethodDefs thread-safe
1 parent be6352d commit 5ee5e58

File tree

6 files changed

+101
-65
lines changed

6 files changed

+101
-65
lines changed

src/Compiler/AbstractIL/il.fs

Lines changed: 32 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2142,39 +2142,35 @@ type ILMethodDef
21422142
type MethodDefMap = Map<string, ILMethodDef list>
21432143

21442144
[<Sealed>]
2145-
type ILMethodDefs(f: unit -> ILMethodDef[]) =
2145+
type ILMethodDefs(f) =
2146+
inherit DelayInitArrayMap<ILMethodDef, string, ILMethodDef list>(f)
21462147

2147-
let mutable array = InlineDelayInit<_>(f)
2148+
override this.CreateDictionary(arr) =
2149+
let t = Dictionary(arr.Length)
21482150

2149-
let mutable dict =
2150-
InlineDelayInit<_>(fun () ->
2151-
let arr = array.Value
2152-
let t = Dictionary<_, _>()
2151+
for i = arr.Length - 1 downto 0 do
2152+
let y = arr[i]
2153+
let key = y.Name
21532154

2154-
for i = arr.Length - 1 downto 0 do
2155-
let y = arr[i]
2156-
let key = y.Name
2155+
match t.TryGetValue key with
2156+
| true, m -> t[key] <- y :: m
2157+
| _ -> t[key] <- [ y ]
21572158

2158-
match t.TryGetValue key with
2159-
| true, m -> t[key] <- y :: m
2160-
| _ -> t[key] <- [ y ]
2161-
2162-
t)
2159+
t
21632160

21642161
interface IEnumerable with
21652162
member x.GetEnumerator() =
21662163
((x :> IEnumerable<ILMethodDef>).GetEnumerator() :> IEnumerator)
21672164

21682165
interface IEnumerable<ILMethodDef> with
21692166
member x.GetEnumerator() =
2170-
(array.Value :> IEnumerable<ILMethodDef>).GetEnumerator()
2171-
2172-
member x.AsArray() = array.Value
2167+
(x.GetArray() :> IEnumerable<ILMethodDef>).GetEnumerator()
21732168

2174-
member x.AsList() = array.Value |> Array.toList
2169+
member x.AsArray() = x.GetArray()
2170+
member x.AsList() = x.GetArray() |> Array.toList
21752171

21762172
member x.FindByName nm =
2177-
match dict.Value.TryGetValue nm with
2173+
match x.GetDictionary().TryGetValue nm with
21782174
| true, m -> m
21792175
| _ -> []
21802176

@@ -2830,43 +2826,40 @@ type ILTypeDef
28302826
override x.ToString() = "type " + x.Name
28312827

28322828
and [<Sealed>] ILTypeDefs(f: unit -> ILPreTypeDef[]) =
2829+
inherit DelayInitArrayMap<ILPreTypeDef, string list * string, ILPreTypeDef>(f)
28332830

2834-
let mutable array = InlineDelayInit<_>(f)
2831+
override this.CreateDictionary(arr) =
2832+
let t = Dictionary(arr.Length, HashIdentity.Structural)
28352833

2836-
let mutable dict =
2837-
InlineDelayInit<_>(fun () ->
2838-
let arr = array.Value
2839-
let t = Dictionary<_, _>(HashIdentity.Structural)
2834+
for pre in arr do
2835+
let key = pre.Namespace, pre.Name
2836+
t[key] <- pre
28402837

2841-
for pre in arr do
2842-
let key = pre.Namespace, pre.Name
2843-
t[key] <- pre
2838+
ReadOnlyDictionary t
28442839

2845-
ReadOnlyDictionary t)
2840+
member x.AsArray() =
2841+
[| for pre in x.GetArray() -> pre.GetTypeDef() |]
28462842

2847-
member _.AsArray() =
2848-
[| for pre in array.Value -> pre.GetTypeDef() |]
2849-
2850-
member _.AsList() =
2851-
[ for pre in array.Value -> pre.GetTypeDef() ]
2843+
member x.AsList() =
2844+
[ for pre in x.GetArray() -> pre.GetTypeDef() ]
28522845

28532846
interface IEnumerable with
28542847
member x.GetEnumerator() =
28552848
((x :> IEnumerable<ILTypeDef>).GetEnumerator() :> IEnumerator)
28562849

28572850
interface IEnumerable<ILTypeDef> with
28582851
member x.GetEnumerator() =
2859-
(seq { for pre in array.Value -> pre.GetTypeDef() }).GetEnumerator()
2852+
(seq { for pre in x.GetArray() -> pre.GetTypeDef() }).GetEnumerator()
28602853

2861-
member _.AsArrayOfPreTypeDefs() = array.Value
2854+
member x.AsArrayOfPreTypeDefs() = x.GetArray()
28622855

2863-
member _.FindByName nm =
2856+
member x.FindByName nm =
28642857
let ns, n = splitILTypeName nm
2865-
dict.Value[ (ns, n) ].GetTypeDef()
2858+
x.GetDictionary().[(ns, n)].GetTypeDef()
28662859

2867-
member _.ExistsByName nm =
2860+
member x.ExistsByName nm =
28682861
let ns, n = splitILTypeName nm
2869-
dict.Value.ContainsKey((ns, n))
2862+
x.GetDictionary().ContainsKey((ns, n))
28702863

28712864
and [<NoEquality; NoComparison>] ILPreTypeDef =
28722865
abstract Namespace: string list

src/Compiler/AbstractIL/il.fsi

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ module rec FSharp.Compiler.AbstractIL.IL
77
open FSharp.Compiler.IO
88
open System.Collections.Generic
99
open System.Reflection
10+
open Internal.Utilities.Library
1011

1112
/// Represents the target primary assembly
1213
[<RequireQualifiedAccess>]
@@ -1179,8 +1180,9 @@ type ILMethodDef =
11791180
/// Tables of methods. Logically equivalent to a list of methods but
11801181
/// the table is kept in a form optimized for looking up methods by
11811182
/// name and arity.
1182-
[<NoEquality; NoComparison; Sealed>]
1183+
[<NoEquality; NoComparison; Class; Sealed>]
11831184
type ILMethodDefs =
1185+
inherit DelayInitArrayMap<ILMethodDef, string, ILMethodDef list>
11841186

11851187
interface IEnumerable<ILMethodDef>
11861188

@@ -1458,8 +1460,10 @@ type ILTypeDefKind =
14581460
| Delegate
14591461

14601462
/// Tables of named type definitions.
1461-
[<NoEquality; NoComparison; Sealed>]
1463+
[<NoEquality; NoComparison; Class; Sealed>]
14621464
type ILTypeDefs =
1465+
inherit DelayInitArrayMap<ILPreTypeDef, string list * string, ILPreTypeDef>
1466+
14631467
interface IEnumerable<ILTypeDef>
14641468

14651469
member internal AsArray: unit -> ILTypeDef[]

src/Compiler/Utilities/illib.fs

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -115,25 +115,51 @@ module internal PervasiveAutoOpens =
115115

116116
task.Result
117117

118-
/// An efficient lazy for inline storage in a class type. Results in fewer thunks.
119-
[<Struct>]
120-
type InlineDelayInit<'T when 'T: not struct> =
121-
new(f: unit -> 'T) =
122-
{
123-
store = Unchecked.defaultof<'T>
124-
func = Func<_>(f)
125-
}
118+
[<AbstractClass>]
119+
type DelayInitArrayMap<'T, 'TDictKey, 'TDictValue>(f: unit -> 'T[]) =
120+
let syncObj = obj ()
121+
122+
let mutable arrayStore = null
123+
let mutable dictStore = null
124+
125+
let mutable func = f
126+
127+
member this.GetArray() =
128+
match arrayStore with
129+
| NonNull value -> value
130+
| _ ->
131+
Monitor.Enter(syncObj)
132+
133+
try
134+
match arrayStore with
135+
| NonNull value -> value
136+
| _ ->
137+
138+
arrayStore <- func ()
126139

127-
val mutable store: 'T
128-
val mutable func: Func<'T> MaybeNull
140+
func <- Unchecked.defaultof<_>
141+
arrayStore
142+
finally
143+
Monitor.Exit(syncObj)
129144

130-
member x.Value =
131-
match x.func with
132-
| null -> x.store
145+
member this.GetDictionary() =
146+
match dictStore with
147+
| NonNull value -> value
133148
| _ ->
134-
let res = LazyInitializer.EnsureInitialized(&x.store, x.func)
135-
x.func <- null
136-
res
149+
let array = this.GetArray()
150+
Monitor.Enter(syncObj)
151+
152+
try
153+
match dictStore with
154+
| NonNull value -> value
155+
| _ ->
156+
157+
dictStore <- this.CreateDictionary(array)
158+
dictStore
159+
finally
160+
Monitor.Exit(syncObj)
161+
162+
abstract CreateDictionary: 'T[] -> IDictionary<'TDictKey, 'TDictValue>
137163

138164
//-------------------------------------------------------------------------
139165
// Library: projections

src/Compiler/Utilities/illib.fsi

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,14 @@ module internal PervasiveAutoOpens =
7070

7171
val notFound: unit -> 'a
7272

73-
[<Struct>]
74-
type internal InlineDelayInit<'T when 'T: not struct> =
73+
[<AbstractClass>]
74+
type DelayInitArrayMap<'T, 'TDictKey, 'TDictValue> =
75+
new: f: (unit -> 'T[]) -> DelayInitArrayMap<'T, 'TDictKey, 'TDictValue>
76+
77+
member GetArray: unit -> 'T[]
78+
member GetDictionary: unit -> IDictionary<'TDictKey, 'TDictValue>
7579

76-
new: f: (unit -> 'T) -> InlineDelayInit<'T>
77-
val mutable store: 'T
78-
val mutable func: Func<'T>
79-
member Value: 'T
80+
abstract CreateDictionary: 'T[] -> IDictionary<'TDictKey, 'TDictValue>
8081

8182
module internal Order =
8283

tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,7 @@ FSharp.Compiler.AbstractIL.IL+ILMethodDefs: ILMethodDef[] AsArray()
799799
FSharp.Compiler.AbstractIL.IL+ILMethodDefs: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILMethodDef] AsList()
800800
FSharp.Compiler.AbstractIL.IL+ILMethodDefs: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILMethodDef] FindByName(System.String)
801801
FSharp.Compiler.AbstractIL.IL+ILMethodDefs: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.AbstractIL.IL+ILMethodDef] TryFindInstanceByNameAndCallingSignature(System.String, ILCallingSignature)
802+
FSharp.Compiler.AbstractIL.IL+ILMethodDefs: System.Collections.Generic.IDictionary`2[System.String,Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILMethodDef]] CreateDictionary(ILMethodDef[])
802803
FSharp.Compiler.AbstractIL.IL+ILMethodImplDef: Boolean Equals(ILMethodImplDef)
803804
FSharp.Compiler.AbstractIL.IL+ILMethodImplDef: Boolean Equals(System.Object)
804805
FSharp.Compiler.AbstractIL.IL+ILMethodImplDef: Boolean Equals(System.Object, System.Collections.IEqualityComparer)
@@ -1619,6 +1620,7 @@ FSharp.Compiler.AbstractIL.IL+ILTypeDefLayout: Int32 GetHashCode(System.Collecti
16191620
FSharp.Compiler.AbstractIL.IL+ILTypeDefLayout: Int32 Tag
16201621
FSharp.Compiler.AbstractIL.IL+ILTypeDefLayout: Int32 get_Tag()
16211622
FSharp.Compiler.AbstractIL.IL+ILTypeDefLayout: System.String ToString()
1623+
FSharp.Compiler.AbstractIL.IL+ILTypeDefs: System.Collections.Generic.IDictionary`2[System.Tuple`2[Microsoft.FSharp.Collections.FSharpList`1[System.String],System.String],FSharp.Compiler.AbstractIL.IL+ILPreTypeDef] CreateDictionary(ILPreTypeDef[])
16221624
FSharp.Compiler.AbstractIL.IL+ILTypeInit+Tags: Int32 BeforeField
16231625
FSharp.Compiler.AbstractIL.IL+ILTypeInit+Tags: Int32 OnAny
16241626
FSharp.Compiler.AbstractIL.IL+ILTypeInit: Boolean Equals(ILTypeInit)
@@ -11710,4 +11712,8 @@ FSharp.Compiler.Xml.XmlDoc: System.String GetXmlText()
1171011712
FSharp.Compiler.Xml.XmlDoc: System.String[] GetElaboratedXmlLines()
1171111713
FSharp.Compiler.Xml.XmlDoc: System.String[] UnprocessedLines
1171211714
FSharp.Compiler.Xml.XmlDoc: System.String[] get_UnprocessedLines()
11713-
FSharp.Compiler.Xml.XmlDoc: Void .ctor(System.String[], FSharp.Compiler.Text.Range)
11715+
FSharp.Compiler.Xml.XmlDoc: Void .ctor(System.String[], FSharp.Compiler.Text.Range)
11716+
Internal.Utilities.Library.DelayInitArrayMap`3[T,TDictKey,TDictValue]: System.Collections.Generic.IDictionary`2[TDictKey,TDictValue] CreateDictionary(T[])
11717+
Internal.Utilities.Library.DelayInitArrayMap`3[T,TDictKey,TDictValue]: System.Collections.Generic.IDictionary`2[TDictKey,TDictValue] GetDictionary()
11718+
Internal.Utilities.Library.DelayInitArrayMap`3[T,TDictKey,TDictValue]: T[] GetArray()
11719+
Internal.Utilities.Library.DelayInitArrayMap`3[T,TDictKey,TDictValue]: Void .ctor(Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,T[]])

tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,7 @@ FSharp.Compiler.AbstractIL.IL+ILMethodDefs: ILMethodDef[] AsArray()
799799
FSharp.Compiler.AbstractIL.IL+ILMethodDefs: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILMethodDef] AsList()
800800
FSharp.Compiler.AbstractIL.IL+ILMethodDefs: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILMethodDef] FindByName(System.String)
801801
FSharp.Compiler.AbstractIL.IL+ILMethodDefs: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.AbstractIL.IL+ILMethodDef] TryFindInstanceByNameAndCallingSignature(System.String, ILCallingSignature)
802+
FSharp.Compiler.AbstractIL.IL+ILMethodDefs: System.Collections.Generic.IDictionary`2[System.String,Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILMethodDef]] CreateDictionary(ILMethodDef[])
802803
FSharp.Compiler.AbstractIL.IL+ILMethodImplDef: Boolean Equals(ILMethodImplDef)
803804
FSharp.Compiler.AbstractIL.IL+ILMethodImplDef: Boolean Equals(System.Object)
804805
FSharp.Compiler.AbstractIL.IL+ILMethodImplDef: Boolean Equals(System.Object, System.Collections.IEqualityComparer)
@@ -1619,6 +1620,7 @@ FSharp.Compiler.AbstractIL.IL+ILTypeDefLayout: Int32 GetHashCode(System.Collecti
16191620
FSharp.Compiler.AbstractIL.IL+ILTypeDefLayout: Int32 Tag
16201621
FSharp.Compiler.AbstractIL.IL+ILTypeDefLayout: Int32 get_Tag()
16211622
FSharp.Compiler.AbstractIL.IL+ILTypeDefLayout: System.String ToString()
1623+
FSharp.Compiler.AbstractIL.IL+ILTypeDefs: System.Collections.Generic.IDictionary`2[System.Tuple`2[Microsoft.FSharp.Collections.FSharpList`1[System.String],System.String],FSharp.Compiler.AbstractIL.IL+ILPreTypeDef] CreateDictionary(ILPreTypeDef[])
16221624
FSharp.Compiler.AbstractIL.IL+ILTypeInit+Tags: Int32 BeforeField
16231625
FSharp.Compiler.AbstractIL.IL+ILTypeInit+Tags: Int32 OnAny
16241626
FSharp.Compiler.AbstractIL.IL+ILTypeInit: Boolean Equals(ILTypeInit)
@@ -11710,4 +11712,8 @@ FSharp.Compiler.Xml.XmlDoc: System.String GetXmlText()
1171011712
FSharp.Compiler.Xml.XmlDoc: System.String[] GetElaboratedXmlLines()
1171111713
FSharp.Compiler.Xml.XmlDoc: System.String[] UnprocessedLines
1171211714
FSharp.Compiler.Xml.XmlDoc: System.String[] get_UnprocessedLines()
11713-
FSharp.Compiler.Xml.XmlDoc: Void .ctor(System.String[], FSharp.Compiler.Text.Range)
11715+
FSharp.Compiler.Xml.XmlDoc: Void .ctor(System.String[], FSharp.Compiler.Text.Range)
11716+
Internal.Utilities.Library.DelayInitArrayMap`3[T,TDictKey,TDictValue]: System.Collections.Generic.IDictionary`2[TDictKey,TDictValue] CreateDictionary(T[])
11717+
Internal.Utilities.Library.DelayInitArrayMap`3[T,TDictKey,TDictValue]: System.Collections.Generic.IDictionary`2[TDictKey,TDictValue] GetDictionary()
11718+
Internal.Utilities.Library.DelayInitArrayMap`3[T,TDictKey,TDictValue]: T[] GetArray()
11719+
Internal.Utilities.Library.DelayInitArrayMap`3[T,TDictKey,TDictValue]: Void .ctor(Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,T[]])

0 commit comments

Comments
 (0)