Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

go/types, types2: fix SizesFor("gc", ...) to match actual gc behavior #61035

Closed
griesemer opened this issue Jun 27, 2023 · 31 comments
Closed

go/types, types2: fix SizesFor("gc", ...) to match actual gc behavior #61035

griesemer opened this issue Jun 27, 2023 · 31 comments

Comments

@griesemer
Copy link
Contributor

griesemer commented Jun 27, 2023

Replace https://go.dev/cl/501495 with proper fix in go/types.

@griesemer griesemer added this to the Go1.21 milestone Jun 27, 2023
@griesemer griesemer self-assigned this Jun 27, 2023
@griesemer griesemer added NeedsFix The path to resolution is known, but the work has not been done. and removed release-blocker labels Jun 27, 2023
@gopherbot
Copy link

Change https://go.dev/cl/506715 mentions this issue: go/types, types2: add Sizes that match actual gc behavior

@gopherbot
Copy link

Change https://go.dev/cl/506716 mentions this issue: cmd/compile: use types2.Sizes instead of compiler own implementation

@gopherbot
Copy link

Change https://go.dev/cl/506856 mentions this issue: go/types, types2: add Sizes that match actual gc behavior

@dmitshur dmitshur modified the milestones: Go1.21, Go1.22 Jun 28, 2023
@dmitshur dmitshur added the early-in-cycle A change that should be done early in the 3 month dev cycle. label Jun 28, 2023
@griesemer
Copy link
Contributor Author

For future reference: The typechecker's StdSizes documentation explains how sizes are computed. If we want to use it for gc sizes, we need to either update the documentation for array and struct sizes, or add a flag to StdSizes that allows clients to choose the new behavior.

https://go.dev/cl/506856 already has an implementation that uses an internal (const) flag to select the appropriate sizes computation. We could simply move this flag into the StdSizes struct and expose it as a field. This way we don't change the existing behavior for backward-compatibility and also can enable the new behavior as needed.

@rsc rsc changed the title go/types, types2: fix SizesFor("gc", ...) to match actual gc behavior proposal: go/types, types2: fix SizesFor("gc", ...) to match actual gc behavior Jun 28, 2023
@rsc rsc modified the milestones: Go1.22, Proposal Jun 28, 2023
@rsc
Copy link
Contributor

rsc commented Jun 28, 2023

Kicking over to proposal process for minor API change (even if the only change is in doc comments).

@dmitshur dmitshur added Proposal and removed NeedsFix The path to resolution is known, but the work has not been done. early-in-cycle A change that should be done early in the 3 month dev cycle. labels Jun 29, 2023
@rsc
Copy link
Contributor

rsc commented Jul 5, 2023

Worth noting that we cannot return a different type from SizesFor, because x/tools/go/package assumes StdSizes:

		// types.SizesFor always returns nil or a *types.StdSizes.
		response.dr.Sizes, _ = sizes.(*types.StdSizes)

@cuonglm
Copy link
Member

cuonglm commented Jul 5, 2023

Worth noting that we cannot return a different type from SizesFor, because x/tools/go/package assumes StdSizes:

		// types.SizesFor always returns nil or a *types.StdSizes.
		response.dr.Sizes, _ = sizes.(*types.StdSizes)

Yeah, I realized this when doing https://go-review.googlesource.com/c/go/+/506856.

@rsc
Copy link
Contributor

rsc commented Jul 5, 2023

The two choices here are:

  1. Change the behavior of StdSizes to match the gc and gccgo compilers, assuming they agree.
  2. OR, add a new flag field to StdSizes to control which "standard" to use.

It would be highly preferable to do (1), assuming gc and gccgo do agree and go/types is the current outlier.

@ianlancetaylor do you know whether gc and gccgo disagree about any specific type size calculations?

@rsc
Copy link
Contributor

rsc commented Jul 5, 2023

This proposal has been added to the active column of the proposals project
and will now be reviewed at the weekly proposal review meetings.
— rsc for the proposal review group

@ianlancetaylor
Copy link
Contributor

The gofrontend code used by gccgo and GoLLVM lets the backend determine the sizes of all types. The effect is that gccgo and GoLLVM use the C ABI on all platforms. This does indeed mean different type characteristics in some cases, though they are mostly the same.

For example for GOARCH=386 this programs prints 4 with the gc compiler and 8 with the gccgo compiler.

package main

import (
	"fmt"
	"unsafe"
)

func main() {
	fmt.Println(unsafe.Alignof(float64(0)))
}

@cuonglm
Copy link
Member

cuonglm commented Jul 12, 2023

@ianlancetaylor It seems to me that the only difference between gc and gccgo in StdSizes implementation is how word size and max align are setup. For example, this program prints 4 for both gc and gccgo:

package main

import (
	"go/types"
)

func main() {
	println(types.SizesFor("gc", "386").Alignof(types.Typ[types.Float64]))
	println(types.SizesFor("gccgo", "386").Alignof(types.Typ[types.Float64]))
}

So probably we could just go for (1) in @rsc 's comment.

cc @griesemer

@rsc
Copy link
Contributor

rsc commented Jul 12, 2023

It sounds like we cannot make StdSizes return numbers matching gc and gccgo because the two don't match.
So we need some indication in the StdSizes struct for which algorithm we're using.

The constraints are that types.SizesFor returns a *StdSizes, and so it needs to return the StdSizes filled out differently for SizesFor("gc", "386") and SizesFor("gccgo", "386"), but we need to know what extra information to add to StdSizes.

(We'd rather not have 'Compiler string' in StdSizes. It seems better to have the specific details from the algorithm, and let the compiler name be "compiled away" by SizesFor.)

@zephyrtronium
Copy link
Contributor

Worth noting that we cannot return a different type from SizesFor, because x/tools/go/package assumes StdSizes:

		// types.SizesFor always returns nil or a *types.StdSizes.
		response.dr.Sizes, _ = sizes.(*types.StdSizes)

I don't see why this means SizesFor cannot return a different type. SizesFor was never documented to always return a *StdSizes. I would call this x/tools/go/package depending on an implementation detail. Is it really easier to change the definition of StdSizes for everyone than to fix the assumption in x/tools?

@ianlancetaylor
Copy link
Contributor

On linux-ppc64le, this program changes behavior with gc and gccgo.

package main

import (
       "fmt"
       "unsafe"
)

type S struct {
     b byte
     f float64
}

func main() {
	fmt.Println(unsafe.Sizeof(S{}), unsafe.Offsetof(S{}.f))
}

With the gc compiler this prints 16 8, with gccgo with the -malign-power option it prints 12 4. (Tested on a linux-ppc64le system). Note that for gccgo this only applies to fields in structs; the alignment of a standalone float64 variable is 8.

On 32-bit ARM, with the -mabi=aapcs option, gccgo will align struct fields of type int64 or float64 or uint64 to a 64-bit boundary, but gc will align them to a 32-bit boundary. The same is true on 32-bit MIPS by default. (I didn't test this, though.)

I wasn't able to quickly find other examples where gc and gccgo will lay out structs differently.

Since gccgo will change struct field layout depending on command line options, it's more or less impossible to have a fully accurate general implementation of types.Sizes for gccgo. In particular there is no StdSizes value that will work.
People who really care will have to pass in their own implementation of the types.Sizes interface.

Currently in go/types we get slightly different results for arm, mips, and mipsle. For each of those gc uses a MaxAlign of 4 and gccgo uses a MaxAlign of 8. That seems accurate for the default gccgo options.

So if we want to be fully accurate, I think we need to permit users to pass in their own types.Sizes implementation, as the go/types package permits, and we need to change x/tools/go/packages to not assume StdSizes is the only possibility. I don't know how difficult the latter change is. Presumably the type would have to be JSON serializable.

@cuonglm
Copy link
Member

cuonglm commented Jul 13, 2023

Given the fact that StdSizes calculation is already not compatible with gccgo:

types.SizesFor("gccgo", "386").Alignof(types.Typ[types.Float64]) // 4

and:

println(unsafe.Alignof(float64(0))) // print 8 with gccgo

maybe we could just deprecate gccgo argument to SizesFor, and make StdSizes always use gc calculation. Then adding a note that users who want to match gccgo behavior should pass its own types.Sizes implementation like @ianlancetaylor said above.

@gopherbot
Copy link

Change https://go.dev/cl/511195 mentions this issue: go/packages: avoid unnecessary dependency on StdSizes

@rsc rsc modified the milestones: Proposal, Backlog Aug 9, 2023
gopherbot pushed a commit to golang/tools that referenced this issue Aug 14, 2023
Nothing ever promised SizesFor would return a *StdSizes.

Updates golang/go#61035

Change-Id: Ib54a7c9d4898cd435e87aea32067a9cfa6975367
Reviewed-on: https://go-review.googlesource.com/c/tools/+/516917
Auto-Submit: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Russ Cox <rsc@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
gopls-CI: kokoro <noreply+kokoro@google.com>
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Michael Matloob <matloob@golang.org>
@gopherbot
Copy link

Change https://go.dev/cl/519295 mentions this issue: gopls/internal/lsp/cache: avoid dependency on StdSizes

gopherbot pushed a commit to golang/tools that referenced this issue Aug 15, 2023
Same as CL 516917, but for gopls.

Updates golang/go#61035

Change-Id: Id6cc1d84f7cac06e95a1fb151a7c3f9a8ef25302
Reviewed-on: https://go-review.googlesource.com/c/tools/+/519295
gopls-CI: kokoro <noreply+kokoro@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Auto-Submit: Cuong Manh Le <cuong.manhle.vn@gmail.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
@dmitshur dmitshur modified the milestones: Backlog, Go1.22 Aug 16, 2023
gopherbot pushed a commit that referenced this issue Aug 16, 2023
With #61035 fixed, types2.Sizes matches the compiler behavior, so use its
Sizes implementation instead of rolling our own copy.

Updates #61035

Change-Id: I7b9efd27a01f729a04c79cd6b4ee5f417fe6e664
Reviewed-on: https://go-review.googlesource.com/c/go/+/506716
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
@gopherbot
Copy link

Change https://go.dev/cl/520435 mentions this issue: cmd: go get golang.org/x/tools@74c255b and revendor

gopherbot pushed a commit that referenced this issue Aug 17, 2023
go get golang.org/x/tools@74c255b # CL 519295
go mod tidy
go mod vendor

Pulling in the fix for unnecessary dependency on *types.StdSizes, which
is non guaranteed behavior.

Updates #61035

Change-Id: Ifb04bab060343b6a849980db6bb65da9889b4665
Reviewed-on: https://go-review.googlesource.com/c/go/+/520435
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Bryan Mills <bcmills@google.com>
Auto-Submit: Bryan Mills <bcmills@google.com>
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
@gopherbot
Copy link

Change https://go.dev/cl/520835 mentions this issue: all: upgrade x/tools and its dependencies

@gopherbot
Copy link

Change https://go.dev/cl/520855 mentions this issue: all: upgrade x/tools and its dependencies

gopherbot pushed a commit to golang/pkgsite-metrics that referenced this issue Aug 18, 2023
This picks up CL 516917 to fix test failures in internal/worker.

For golang/go#61035.

Change-Id: I1d7162f2775548423647f7b00ccdc8d860afdc97
Reviewed-on: https://go-review.googlesource.com/c/pkgsite-metrics/+/520855
Run-TryBot: Bryan Mills <bcmills@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Bryan Mills <bcmills@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
gopherbot pushed a commit to golang/mobile that referenced this issue Aug 18, 2023
This picks up CL 516917 to fix test failures in cmd/gobind.

For golang/go#61035.

Change-Id: Ibecb7ace6ce9133a25559191ee6075bbb714a7d7
Reviewed-on: https://go-review.googlesource.com/c/mobile/+/520835
Reviewed-by: Robert Findley <rfindley@google.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Run-TryBot: Bryan Mills <bcmills@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Bryan Mills <bcmills@google.com>
@bcmills
Copy link
Contributor

bcmills commented Aug 18, 2023

We've seen quite a few tests fail in Go subrepos and in Google-internal testing from this.

Is it feasible to add a GODEBUG guarding the fix, so that modules that declare go versions before 1.22 (and don't override GODEBUG explicitly) can retain the old (buggy) behavior?

@cuonglm
Copy link
Member

cuonglm commented Aug 19, 2023

We've seen quite a few tests fail in Go subrepos and in Google-internal testing from this.

Is it feasible to add a GODEBUG guarding the fix, so that modules that declare go versions before 1.22 (and don't override GODEBUG explicitly) can retain the old (buggy) behavior?

I'm not sure it's worth, given Russ's comment here: #61035 (comment)

I think most of the test failed because it's buggy code which is relying on SizesFor always returns StdSizes, we should rather fix them then leaving them continue with buggy behavior.

@gopherbot
Copy link

Change https://go.dev/cl/546837 mentions this issue: doc: add release note for changes to go/types/SizesFor

gopherbot pushed a commit that referenced this issue Dec 5, 2023
For #61035.

Change-Id: I27e2c44f9275b508d9dccc50da80896384a4c8fc
Reviewed-on: https://go-review.googlesource.com/c/go/+/546837
TryBot-Bypass: Robert Griesemer <gri@google.com>
Reviewed-by: Alan Donovan <adonovan@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
ezz-no pushed a commit to ezz-no/go-ezzno that referenced this issue Feb 18, 2024
For golang#61035.

Change-Id: I27e2c44f9275b508d9dccc50da80896384a4c8fc
Reviewed-on: https://go-review.googlesource.com/c/go/+/546837
TryBot-Bypass: Robert Griesemer <gri@google.com>
Reviewed-by: Alan Donovan <adonovan@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Accepted
Development

No branches or pull requests

8 participants