为什么F#generic struct有额外的__dummy字段?

ban*_*low 19 compiler-construction generics f# struct sizeof

使用F#Interactive,您可以验证以下大小:

// sizeof<A> = 4 bytes
type A (i: int) = struct end

// sizeof<B<int>> = 8 bytes (use any type parameter)
type B<'T> (i: int) = struct end
Run Code Online (Sandbox Code Playgroud)

额外大小的原因似乎是__dummy在通用情况下存在整数字段.再次使用F#Interactive,您可以使用typeof以下内容查看:

  • typeof<A> 节目 DeclaredFields = [|Int32 i|]
  • typeof<B<int>> 节目 DeclaredFields = [|Int32 i; Int32 __dummy|]

我不明白为什么要__dummy添加这个字段.

我认为负责添加它的代码在这里:

https://github.com/fsharp/FSharp.Compiler.Service/blob/master/src/fsharp/ilxgen.fs

第6377行显示:

if requiresExtraField then 
    yield mkILInstanceField("__dummy",cenv.g.ilg.typ_int32,None,ILMemberAccess.Assembly) ]
Run Code Online (Sandbox Code Playgroud)

6290行就是requiresExtraField定义:

let requiresExtraField = 
    let isEmptyStruct = 
        (match ilTypeDefKind with ILTypeDefKind.ValueType -> true | _ -> false) &&
        // All structs are sequential by default 
        // Structs with no instance fields get size 1, pack 0
        tycon.AllFieldsAsList |> List.exists (fun f -> not f.IsStatic)

    isEmptyStruct && cenv.opts.workAroundReflectionEmitBugs && not tycon.TyparsNoRange.IsEmpty
Run Code Online (Sandbox Code Playgroud)

我认为这isEmptyStruct应该意味着结构没有任何实例字段.但是编写的代码正在测试结构是否确实具有任何实例字段,对于大多数结构,包括我的结构字段都是如此.我认为最终测试的最后一部分是是否存在任何泛型类型参数.所以,requiresExtraFieldfalsetype A(不是一般的)和truetype B(通用型).

这是编译器错误,还是代码正确?如果它是正确的,那么这个__dummy领域的目的是什么?有什么方法可以避免它吗?

作为另一个测试,我删除了我唯一的实例字段,并且毫不奇怪,我得到以下大小,显示该__dummy字段不再添加:

// sizeof<AA> = 1
type AA = struct end

// sizeof<BB<int>> = 1
type BB<'T> = struct end
Run Code Online (Sandbox Code Playgroud)

我想要一个值类型而不是引用类型的原因是我将在我的数据结构中存储大量这些对象,而不仅仅是传递它们.

ban*_*low 1

@jyoung 在我的原始帖子下面的评论中给出了解释。

最后一行requiresExtraField也进行了测试cenv.opts.workAroundReflectionEmitBugs。该标志似乎是在fscopts.fs中设置的。该行代码是:

workAroundReflectionEmitBugs=tcConfig.isInteractive; // REVIEW: is this still required?
Run Code Online (Sandbox Code Playgroud)

所以额外字段的问题__dummy只出现在F# Interactive中。