Skip to content

cmd/compile: replace //go:notinheap with runtime/internal/sys.NotInHeap #46731

Closed
@mdempsky

Description

@mdempsky

//go:notinheap is the only current type pragma, and it imposes a lot of complexity and special cases on the compiler and tools. E.g., it's not captured within the go/types or types2 type models, so users wanting to analyze code that uses it have to do a lot of effort to reconstruct this information. The reflect API wasn't updated to reject ChanOf or MapOf for notinheap types. Even the existing compiler typechecker that was extended to natively support //go:notinheap fails to handle tricky situations: https://play.golang.org/p/hYGrwJx37TN

//go:notinheap is effectively a language change, but it bypassed review by the usual language spec reviewers because it started out as a runtime-only hack. It was then extended to be used by cmd/cgo and be accessible to user packages (as a necessity of cmd/cgo's design), but again skipped language review.

We already have what are effectively type pragmas in the form of "noCompare" (where embedding a non-comparable, zero-size type makes the enclosing struct non-comparable too) and "noCopy" (where cmd/vet can detect value copies of types that directly contain an element of type "noCopy"). However, they work much more robustly and interoperate with existing tooling better because they rely on struct field embedding, rather than introducing actual type pragmas. I think //go:notinheap should be modified to work similarly.

I propose the following:

  1. Add a new NotInHeap type to runtime/internal/sys. Its initial definition would be:

    type NotInHeap struct { _ nih }
    
    //go:notinheap
    type nih struct{}
    
  2. Disallow all other use of //go:notinheap, and maybe eventually get rid of it altogether by turning sys.NotInHeap into a compiler intrinsic type like unsafe.Pointer.

  3. Change existing runtime types that use //go:notinheap to add a sys.NotInHeap-typed field instead. The handful of defined types that are marked //go:notinheap but aren't already a struct type (i.e., debugLogBuf, checkmarksMap, gcBits) would need to be adjusted to use a struct wrapper.

  4. Add a new runtime/cgo.Incomplete type with the definition: type Incomplete struct { _ sys.NotInHeap }. Change cmd/cgo to emit type _Ctype_struct_foo cgo.Incomplete instead of using struct{} with a //go:notinheap directive.

  5. Disallow the reintroduction of type pragmas, even for runtime use, without proposal review. (I have no objection to runtime-internal intrinsic types though.)

Incidentally, this is also the approach I took in implementing https://go-review.googlesource.com/c/go/+/308971 as a proof of concept of #19057 (adding intrinsic types to allow adjusting field alignment) for use within the runtime. I think it worked cleanly, and it avoided requiring the introduction of new type pragmas. Instead, it added runtime/internal/align.elemT as an intrinsic type known to the compiler with special alignment semantics.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions