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

时间:2014-09-15 12:54:03

标签: generics compiler-construction struct f# 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

额外大小的原因似乎是在通用情况下存在整数__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

Line 6377显示了这一点:

if requiresExtraField then 
    yield mkILInstanceField("__dummy",cenv.g.ilg.typ_int32,None,ILMemberAccess.Assembly) ]

Line 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

我认为isEmptyStruct应该意味着结构没有任何实例字段。但是编写的代码正在测试struct 是否具有任何实例字段,对于大多数结构体,包括我的结构字段都是真的。我认为最终测试的最后一部分是是否存在任何泛型类型参数。因此requiresExtraField falsetype A(非通用),truetype B(通用类型)。{/ p>

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

作为另一项测试,我删除了我唯一的实例字段,毫不奇怪,我得到了以下尺寸,显示不再添加__dummy字段:

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

// sizeof<BB<int>> = 1
type BB<'T> = struct end

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

1 个答案:

答案 0 :(得分:1)

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

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

workAroundReflectionEmitBugs=tcConfig.isInteractive; // REVIEW: is this still required?

因此,额外__dummy字段的问题仅发生在F#Interactive。