Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions docs/release-notes/.FSharp.Compiler.Service/11.0.100.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@
* Add symbol and type highlighting to F# diagnostics ([PR #20097](https://github.com/dotnet/fsharp/pull/20097))
* IL: add `ILPreNamespace`, make `ILPreTypeDef` creation lazy ([PR #20092](https://github.com/dotnet/fsharp/pull/20092))
* IL: use empty tables for members when possible ([PR #20249](https://github.com/dotnet/fsharp/pull/20249))
* IL: hold custom attributes in fields rather than a union case

### Improved

Expand Down
33 changes: 19 additions & 14 deletions src/Compiler/AbstractIL/il.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1262,27 +1262,31 @@ type WellKnownILAttributes =
| OverloadResolutionPriorityAttribute = (1u <<< 26)
| NotComputed = (1u <<< 31)

type internal ILAttributesStoredRepr =
| Reader of (int32 -> ILAttribute[])
| Given of ILAttributes

[<Sealed; NoEquality; NoComparison>]
type ILAttributesStored private (metadataIndex: int32, initial: ILAttributesStoredRepr) =
type ILAttributesStored private (metadataIndex: int32, reader: int32 -> ILAttribute[], given: ILAttribute[] | null) =

/// Stands in for the reader when the attributes are already in hand, so the field can stay non-null.
static let noReader: int32 -> ILAttribute[] = fun _ -> [||]

// Holds the array rather than an ILAttributesStoredRepr. The reader function is shared per metadata
// reader per attribute table, so it is held directly; wrapping it cost one object per owner, and most
// owners are never forced, so most of those existed only to say "not read yet". ILAttributes is a
// struct over the array, so rewrapping on each read allocates nothing.
[<VolatileField>]
let mutable repr = initial
let mutable attrArray: ILAttribute[] | null = given

[<VolatileField>]
let mutable wellKnownFlags = WellKnownILAttributes.NotComputed

member _.MetadataIndex = metadataIndex

member x.CustomAttrs: ILAttributes =
match repr with
| Given a -> a
| Reader f ->
let r = ILAttributes(f metadataIndex)
repr <- Given r
r
match attrArray with
| null ->
let a = reader metadataIndex
attrArray <- a
ILAttributes a
| a -> ILAttributes a

member x.HasWellKnownAttribute(flag: WellKnownILAttributes, compute: ILAttributes -> WellKnownILAttributes) : bool =
x.GetOrComputeWellKnownFlags(compute) &&& flag <> WellKnownILAttributes.None
Expand All @@ -1298,9 +1302,10 @@ type ILAttributesStored private (metadataIndex: int32, initial: ILAttributesStor
wellKnownFlags <- computed
computed

static member CreateReader(idx: int32, f: int32 -> ILAttribute[]) = ILAttributesStored(idx, Reader f)
static member CreateReader(idx: int32, f: int32 -> ILAttribute[]) = ILAttributesStored(idx, f, null)

static member CreateGiven(attrs: ILAttributes) = ILAttributesStored(-1, Given attrs)
static member CreateGiven(attrs: ILAttributes) =
ILAttributesStored(-1, noReader, attrs.AsArray())

let emptyILCustomAttrs = ILAttributes [||]

Expand Down
Loading