diff --git a/src/Compiler/AbstractIL/il.fs b/src/Compiler/AbstractIL/il.fs index 2c96d10f528..93ada135102 100644 --- a/src/Compiler/AbstractIL/il.fs +++ b/src/Compiler/AbstractIL/il.fs @@ -2142,24 +2142,21 @@ type ILMethodDef type MethodDefMap = Map [] -type ILMethodDefs(f: unit -> ILMethodDef[]) = +type ILMethodDefs(f) = + inherit DelayInitArrayMap(f) - let mutable array = InlineDelayInit<_>(f) + override this.CreateDictionary(arr) = + let t = Dictionary(arr.Length) - let mutable dict = - InlineDelayInit<_>(fun () -> - let arr = array.Value - let t = Dictionary<_, _>() + for i = arr.Length - 1 downto 0 do + let y = arr[i] + let key = y.Name - for i = arr.Length - 1 downto 0 do - let y = arr[i] - let key = y.Name + match t.TryGetValue key with + | true, m -> t[key] <- y :: m + | _ -> t[key] <- [ y ] - match t.TryGetValue key with - | true, m -> t[key] <- y :: m - | _ -> t[key] <- [ y ] - - t) + t interface IEnumerable with member x.GetEnumerator() = @@ -2167,14 +2164,13 @@ type ILMethodDefs(f: unit -> ILMethodDef[]) = interface IEnumerable with member x.GetEnumerator() = - (array.Value :> IEnumerable).GetEnumerator() - - member x.AsArray() = array.Value + (x.GetArray() :> IEnumerable).GetEnumerator() - member x.AsList() = array.Value |> Array.toList + member x.AsArray() = x.GetArray() + member x.AsList() = x.GetArray() |> Array.toList member x.FindByName nm = - match dict.Value.TryGetValue nm with + match x.GetDictionary().TryGetValue nm with | true, m -> m | _ -> [] @@ -2830,25 +2826,22 @@ type ILTypeDef override x.ToString() = "type " + x.Name and [] ILTypeDefs(f: unit -> ILPreTypeDef[]) = + inherit DelayInitArrayMap(f) - let mutable array = InlineDelayInit<_>(f) + override this.CreateDictionary(arr) = + let t = Dictionary(arr.Length, HashIdentity.Structural) - let mutable dict = - InlineDelayInit<_>(fun () -> - let arr = array.Value - let t = Dictionary<_, _>(HashIdentity.Structural) + for pre in arr do + let key = pre.Namespace, pre.Name + t[key] <- pre - for pre in arr do - let key = pre.Namespace, pre.Name - t[key] <- pre + ReadOnlyDictionary t - ReadOnlyDictionary t) + member x.AsArray() = + [| for pre in x.GetArray() -> pre.GetTypeDef() |] - member _.AsArray() = - [| for pre in array.Value -> pre.GetTypeDef() |] - - member _.AsList() = - [ for pre in array.Value -> pre.GetTypeDef() ] + member x.AsList() = + [ for pre in x.GetArray() -> pre.GetTypeDef() ] interface IEnumerable with member x.GetEnumerator() = @@ -2856,17 +2849,17 @@ and [] ILTypeDefs(f: unit -> ILPreTypeDef[]) = interface IEnumerable with member x.GetEnumerator() = - (seq { for pre in array.Value -> pre.GetTypeDef() }).GetEnumerator() + (seq { for pre in x.GetArray() -> pre.GetTypeDef() }).GetEnumerator() - member _.AsArrayOfPreTypeDefs() = array.Value + member x.AsArrayOfPreTypeDefs() = x.GetArray() - member _.FindByName nm = + member x.FindByName nm = let ns, n = splitILTypeName nm - dict.Value[ (ns, n) ].GetTypeDef() + x.GetDictionary().[(ns, n)].GetTypeDef() - member _.ExistsByName nm = + member x.ExistsByName nm = let ns, n = splitILTypeName nm - dict.Value.ContainsKey((ns, n)) + x.GetDictionary().ContainsKey((ns, n)) and [] ILPreTypeDef = abstract Namespace: string list diff --git a/src/Compiler/AbstractIL/il.fsi b/src/Compiler/AbstractIL/il.fsi index 34e7d8584e2..37bfd87e4ae 100644 --- a/src/Compiler/AbstractIL/il.fsi +++ b/src/Compiler/AbstractIL/il.fsi @@ -7,6 +7,7 @@ module rec FSharp.Compiler.AbstractIL.IL open FSharp.Compiler.IO open System.Collections.Generic open System.Reflection +open Internal.Utilities.Library /// Represents the target primary assembly [] @@ -1179,8 +1180,9 @@ type ILMethodDef = /// Tables of methods. Logically equivalent to a list of methods but /// the table is kept in a form optimized for looking up methods by /// name and arity. -[] +[] type ILMethodDefs = + inherit DelayInitArrayMap interface IEnumerable @@ -1458,8 +1460,10 @@ type ILTypeDefKind = | Delegate /// Tables of named type definitions. -[] +[] type ILTypeDefs = + inherit DelayInitArrayMap + interface IEnumerable member internal AsArray: unit -> ILTypeDef[] diff --git a/src/Compiler/Utilities/illib.fs b/src/Compiler/Utilities/illib.fs index a0db105d145..776525e32b0 100644 --- a/src/Compiler/Utilities/illib.fs +++ b/src/Compiler/Utilities/illib.fs @@ -118,25 +118,51 @@ module internal PervasiveAutoOpens = task.Result -/// An efficient lazy for inline storage in a class type. Results in fewer thunks. -[] -type InlineDelayInit<'T when 'T: not struct> = - new(f: unit -> 'T) = - { - store = Unchecked.defaultof<'T> - func = Func<_>(f) - } +[] +type DelayInitArrayMap<'T, 'TDictKey, 'TDictValue>(f: unit -> 'T[]) = + let syncObj = obj () + + let mutable arrayStore = null + let mutable dictStore = null + + let mutable func = f + + member this.GetArray() = + match arrayStore with + | NonNull value -> value + | _ -> + Monitor.Enter(syncObj) + + try + match arrayStore with + | NonNull value -> value + | _ -> + + arrayStore <- func () - val mutable store: 'T - val mutable func: Func<'T> MaybeNull + func <- Unchecked.defaultof<_> + arrayStore + finally + Monitor.Exit(syncObj) - member x.Value = - match x.func with - | null -> x.store + member this.GetDictionary() = + match dictStore with + | NonNull value -> value | _ -> - let res = LazyInitializer.EnsureInitialized(&x.store, x.func) - x.func <- null - res + let array = this.GetArray() + Monitor.Enter(syncObj) + + try + match dictStore with + | NonNull value -> value + | _ -> + + dictStore <- this.CreateDictionary(array) + dictStore + finally + Monitor.Exit(syncObj) + + abstract CreateDictionary: 'T[] -> IDictionary<'TDictKey, 'TDictValue> //------------------------------------------------------------------------- // Library: projections diff --git a/src/Compiler/Utilities/illib.fsi b/src/Compiler/Utilities/illib.fsi index bb41d9c490f..ade6e3205cd 100644 --- a/src/Compiler/Utilities/illib.fsi +++ b/src/Compiler/Utilities/illib.fsi @@ -70,13 +70,14 @@ module internal PervasiveAutoOpens = val notFound: unit -> 'a -[] -type internal InlineDelayInit<'T when 'T: not struct> = +[] +type DelayInitArrayMap<'T, 'TDictKey, 'TDictValue> = + new: f: (unit -> 'T[]) -> DelayInitArrayMap<'T, 'TDictKey, 'TDictValue> + + member GetArray: unit -> 'T[] + member GetDictionary: unit -> IDictionary<'TDictKey, 'TDictValue> - new: f: (unit -> 'T) -> InlineDelayInit<'T> - val mutable store: 'T - val mutable func: Func<'T> - member Value: 'T + abstract CreateDictionary: 'T[] -> IDictionary<'TDictKey, 'TDictValue> module internal Order = diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl index e5d58f2ed14..3ed7352ab36 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.debug.bsl @@ -799,6 +799,7 @@ FSharp.Compiler.AbstractIL.IL+ILMethodDefs: ILMethodDef[] AsArray() FSharp.Compiler.AbstractIL.IL+ILMethodDefs: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILMethodDef] AsList() FSharp.Compiler.AbstractIL.IL+ILMethodDefs: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILMethodDef] FindByName(System.String) FSharp.Compiler.AbstractIL.IL+ILMethodDefs: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.AbstractIL.IL+ILMethodDef] TryFindInstanceByNameAndCallingSignature(System.String, ILCallingSignature) +FSharp.Compiler.AbstractIL.IL+ILMethodDefs: System.Collections.Generic.IDictionary`2[System.String,Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILMethodDef]] CreateDictionary(ILMethodDef[]) FSharp.Compiler.AbstractIL.IL+ILMethodImplDef: Boolean Equals(ILMethodImplDef) FSharp.Compiler.AbstractIL.IL+ILMethodImplDef: Boolean Equals(System.Object) 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 FSharp.Compiler.AbstractIL.IL+ILTypeDefLayout: Int32 Tag FSharp.Compiler.AbstractIL.IL+ILTypeDefLayout: Int32 get_Tag() FSharp.Compiler.AbstractIL.IL+ILTypeDefLayout: System.String ToString() +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[]) FSharp.Compiler.AbstractIL.IL+ILTypeInit+Tags: Int32 BeforeField FSharp.Compiler.AbstractIL.IL+ILTypeInit+Tags: Int32 OnAny FSharp.Compiler.AbstractIL.IL+ILTypeInit: Boolean Equals(ILTypeInit) @@ -11707,4 +11709,8 @@ FSharp.Compiler.Xml.XmlDoc: System.String GetXmlText() FSharp.Compiler.Xml.XmlDoc: System.String[] GetElaboratedXmlLines() FSharp.Compiler.Xml.XmlDoc: System.String[] UnprocessedLines FSharp.Compiler.Xml.XmlDoc: System.String[] get_UnprocessedLines() -FSharp.Compiler.Xml.XmlDoc: Void .ctor(System.String[], FSharp.Compiler.Text.Range) \ No newline at end of file +FSharp.Compiler.Xml.XmlDoc: Void .ctor(System.String[], FSharp.Compiler.Text.Range) +Internal.Utilities.Library.DelayInitArrayMap`3[T,TDictKey,TDictValue]: System.Collections.Generic.IDictionary`2[TDictKey,TDictValue] CreateDictionary(T[]) +Internal.Utilities.Library.DelayInitArrayMap`3[T,TDictKey,TDictValue]: System.Collections.Generic.IDictionary`2[TDictKey,TDictValue] GetDictionary() +Internal.Utilities.Library.DelayInitArrayMap`3[T,TDictKey,TDictValue]: T[] GetArray() +Internal.Utilities.Library.DelayInitArrayMap`3[T,TDictKey,TDictValue]: Void .ctor(Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,T[]]) \ No newline at end of file diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl index e5d58f2ed14..3ed7352ab36 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl @@ -799,6 +799,7 @@ FSharp.Compiler.AbstractIL.IL+ILMethodDefs: ILMethodDef[] AsArray() FSharp.Compiler.AbstractIL.IL+ILMethodDefs: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILMethodDef] AsList() FSharp.Compiler.AbstractIL.IL+ILMethodDefs: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILMethodDef] FindByName(System.String) FSharp.Compiler.AbstractIL.IL+ILMethodDefs: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.AbstractIL.IL+ILMethodDef] TryFindInstanceByNameAndCallingSignature(System.String, ILCallingSignature) +FSharp.Compiler.AbstractIL.IL+ILMethodDefs: System.Collections.Generic.IDictionary`2[System.String,Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.AbstractIL.IL+ILMethodDef]] CreateDictionary(ILMethodDef[]) FSharp.Compiler.AbstractIL.IL+ILMethodImplDef: Boolean Equals(ILMethodImplDef) FSharp.Compiler.AbstractIL.IL+ILMethodImplDef: Boolean Equals(System.Object) 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 FSharp.Compiler.AbstractIL.IL+ILTypeDefLayout: Int32 Tag FSharp.Compiler.AbstractIL.IL+ILTypeDefLayout: Int32 get_Tag() FSharp.Compiler.AbstractIL.IL+ILTypeDefLayout: System.String ToString() +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[]) FSharp.Compiler.AbstractIL.IL+ILTypeInit+Tags: Int32 BeforeField FSharp.Compiler.AbstractIL.IL+ILTypeInit+Tags: Int32 OnAny FSharp.Compiler.AbstractIL.IL+ILTypeInit: Boolean Equals(ILTypeInit) @@ -11707,4 +11709,8 @@ FSharp.Compiler.Xml.XmlDoc: System.String GetXmlText() FSharp.Compiler.Xml.XmlDoc: System.String[] GetElaboratedXmlLines() FSharp.Compiler.Xml.XmlDoc: System.String[] UnprocessedLines FSharp.Compiler.Xml.XmlDoc: System.String[] get_UnprocessedLines() -FSharp.Compiler.Xml.XmlDoc: Void .ctor(System.String[], FSharp.Compiler.Text.Range) \ No newline at end of file +FSharp.Compiler.Xml.XmlDoc: Void .ctor(System.String[], FSharp.Compiler.Text.Range) +Internal.Utilities.Library.DelayInitArrayMap`3[T,TDictKey,TDictValue]: System.Collections.Generic.IDictionary`2[TDictKey,TDictValue] CreateDictionary(T[]) +Internal.Utilities.Library.DelayInitArrayMap`3[T,TDictKey,TDictValue]: System.Collections.Generic.IDictionary`2[TDictKey,TDictValue] GetDictionary() +Internal.Utilities.Library.DelayInitArrayMap`3[T,TDictKey,TDictValue]: T[] GetArray() +Internal.Utilities.Library.DelayInitArrayMap`3[T,TDictKey,TDictValue]: Void .ctor(Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,T[]]) \ No newline at end of file