-
Notifications
You must be signed in to change notification settings - Fork 17.6k
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
cmd/compile: special-case MethodByName(string literal) to keep the DCE enabled. #62257
Labels
binary-size
compiler/runtime
Issues related to the Go compiler and/or runtime.
FrozenDueToAge
NeedsFix
The path to resolution is known, but the work has not been done.
Milestone
Comments
gopherbot
added
the
compiler/runtime
Issues related to the Go compiler and/or runtime.
label
Aug 24, 2023
Change https://go.dev/cl/522436 mentions this issue: |
thanm
added
the
NeedsFix
The path to resolution is known, but the work has not been done.
label
Aug 24, 2023
Thanks for sending this. I touched up the reviewer set for your CLs and ran the trybots. |
jquirke
pushed a commit
to jquirke/go
that referenced
this issue
Sep 16, 2023
In deadcode removal in the linker, use of .Method(int) and MethodByName(string) cause the deadcode analysis to give up, due to the intractability of knowing what methods might be used. In golang#62257 there was some compiler assisted optimisation added to special case MethodByName and Method with constant arguments, which at Uber has resulted in fewer transitive packages breaking DCE. However, there are still a number of non trivial cases which we would like to easily identify in our monorepos, and loggign would be useful here.
jquirke
pushed a commit
to jquirke/go
that referenced
this issue
Sep 16, 2023
In deadcode removal in the linker, use of .Method(int) and MethodByName(string) cause the deadcode analysis to give up, due to the intractability of knowing what methods might be used. In golang#62257 there was some compiler assisted optimisation added to special case MethodByName and Method with constant arguments, which at Uber has resulted in fewer transitive packages breaking DCE. However, there are still a number of non trivial cases which we would like to easily identify in our monorepos, and loggign would be useful here.
jquirke
added a commit
to jquirke/go
that referenced
this issue
Sep 16, 2023
In deadcode removal in the linker, use of .Method(int) and MethodByName(string) cause the deadcode analysis to give up, due to the intractability of knowing what methods might be used. In golang#62257 there was some compiler assisted optimisation added to special case MethodByName and Method with constant arguments, which at Uber has resulted in fewer transitive packages breaking DCE. However, there are still a number of non trivial cases which we would like to easily identify in our monorepos, and loggign would be useful here.
Change https://go.dev/cl/528895 mentions this issue: |
jquirke
added a commit
to jquirke/go
that referenced
this issue
Sep 16, 2023
In deadcode removal in the linker, use of .Method(int) and MethodByName(string)cause the deadcode analysis to give up, due to the intractability of knowing what methods might be used. In golang#62257 there was some compiler assisted optimisation added to special case MethodByName and Method with constant arguments, which at Uber has resulted in fewer transitive packages breaking DCE. However, there are still a number of non trivial cases which we would like to easily identify in our monorepos, and logging would be useful here.
jquirke
added a commit
to jquirke/go
that referenced
this issue
Sep 16, 2023
In deadcode removal in the linker, use of .Method(int) and MethodByName(string) cause the deadcode analysis to give up, due to the intractability of knowing what methods might be used. In golang#62257 there was some compiler assisted optimisation added to special case MethodByName and Method with constant arguments, which at Uber has resulted in fewer transitive packages breaking DCE. However, there are still a number of non trivial cases which we would like to easily identify in our monorepos, and logging would be useful here.
jquirke
added a commit
to jquirke/go
that referenced
this issue
Sep 16, 2023
In deadcode removal in the linker, use of .Method(int) and MethodByName(string) cause the deadcode analysis to give up, due to the intractability of knowing what methods might be used. In golang#62257 there was some compiler assisted logic added to special case MethodByName and Method with constant arguments, and avoid marking those as AttrReflectMethod. At Uber has resulted in fewer transitive packages breaking DCE. However, there are still a number of non trivial cases which we would like to easily identify in our monorepos, and logging would be useful here.
jquirke
added a commit
to jquirke/gorm
that referenced
this issue
Sep 17, 2023
Go 1.22 goes somewhat toward addressing the issue of calls to reflection MethodByName disabling linker deadcode elimination (DCE) resulting in huge binaries by using GORM beause the linker cannot prune unused code that *could* be reached via reflection. Go Issue golang/go#62257 reduces the number of incidences by leveraging a compiler assist to avoid marking functions containing calls to MethodByName as ReflectMethods. An analysis of Uber Technologies code base however shows that a number of transitive imports still contain calls to MethodByName with a variable argument. In the case of GORM, the solution we are proposing is because the number of possible methods is finite, we will "unroll" this. This demonstrably shows that GORM is not longer a problem for DCE. ``` Before ``` % go version go version devel go1.22-2f3458a8ce Sat Sep 16 16:26:48 2023 -0700 darwin/arm64 % go test ./... -ldflags='-v=2' 2> >(grep -i 'deadcode: giving up') deadcode: giving up on static analysis due to relect method symbol gorm.io/gorm/schema.ParseWithSpecialTableName<3938> deadcode: giving up on static analysis due to relect method symbol reflect.(*Value).Method<119948> deadcode: giving up on static analysis due to relect method symbol reflect.(*Value).MethodByName<119949> deadcode: giving up on static analysis due to relect method symbol gorm.io/gorm/schema.ParseWithSpecialTableName<49693> deadcode: giving up on static analysis due to relect method symbol reflect.(*Value).Method<117898> deadcode: giving up on static analysis due to relect method symbol reflect.(*Value).MethodByName<117899> deadcode: giving up on static analysis due to relect method symbol gorm.io/gorm/schema.ParseWithSpecialTableName<54029> deadcode: giving up on static analysis due to relect method symbol reflect.(*Value).Method<117635> deadcode: giving up on static analysis due to relect method symbol reflect.(*Value).MethodByName<117636> ok gorm.io/gorm (cached) ok gorm.io/gorm/callbacks (cached) ? gorm.io/gorm/migrator [no test files] ok gorm.io/gorm/clause (cached) ok gorm.io/gorm/logger (cached) ? gorm.io/gorm/utils/tests [no test files] ok gorm.io/gorm/schema (cached) ok gorm.io/gorm/utils (cached) % ``` After ``` % go version go version devel go1.22-2f3458a8ce Sat Sep 16 16:26:48 2023 -0700 darwin/arm64 %go test ./... -ldflags='-v=2' 2> >(grep -i 'deadcode: giving up') ? gorm.io/gorm/migrator [no test files] ? gorm.io/gorm/utils/tests [no test files] ok gorm.io/gorm 0.474s ok gorm.io/gorm/callbacks 0.372s ok gorm.io/gorm/clause 0.605s ok gorm.io/gorm/logger (cached) ok gorm.io/gorm/schema 0.689s ok gorm.io/gorm/utils (cached) % ```
jquirke
added a commit
to jquirke/gorm
that referenced
this issue
Sep 17, 2023
Go 1.22 goes somewhat toward addressing the issue of calls to reflection MethodByName disabling linker deadcode elimination (DCE) resulting in huge binaries by using GORM beause the linker cannot prune unused code that *could* be reached via reflection. Go Issue golang/go#62257 reduces the number of incidences by leveraging a compiler assist to avoid marking functions containing calls to MethodByName as ReflectMethods. An analysis of Uber Technologies code base however shows that a number of transitive imports still contain calls to MethodByName with a variable argument. In the case of GORM, the solution we are proposing is because the number of possible methods is finite, we will "unroll" this. This demonstrably shows that GORM is not longer a problem for DCE. Before ``` % go version go version devel go1.22-2f3458a8ce Sat Sep 16 16:26:48 2023 -0700 darwin/arm64 % go test ./... -ldflags='-v=2' 2> >(grep -i 'deadcode: giving up') deadcode: giving up on static analysis due to relect method symbol gorm.io/gorm/schema.ParseWithSpecialTableName<3938> deadcode: giving up on static analysis due to relect method symbol reflect.(*Value).Method<119948> deadcode: giving up on static analysis due to relect method symbol reflect.(*Value).MethodByName<119949> deadcode: giving up on static analysis due to relect method symbol gorm.io/gorm/schema.ParseWithSpecialTableName<49693> deadcode: giving up on static analysis due to relect method symbol reflect.(*Value).Method<117898> deadcode: giving up on static analysis due to relect method symbol reflect.(*Value).MethodByName<117899> deadcode: giving up on static analysis due to relect method symbol gorm.io/gorm/schema.ParseWithSpecialTableName<54029> deadcode: giving up on static analysis due to relect method symbol reflect.(*Value).Method<117635> deadcode: giving up on static analysis due to relect method symbol reflect.(*Value).MethodByName<117636> ok gorm.io/gorm (cached) ok gorm.io/gorm/callbacks (cached) ? gorm.io/gorm/migrator [no test files] ok gorm.io/gorm/clause (cached) ok gorm.io/gorm/logger (cached) ? gorm.io/gorm/utils/tests [no test files] ok gorm.io/gorm/schema (cached) ok gorm.io/gorm/utils (cached) % ``` After ``` % go version go version devel go1.22-2f3458a8ce Sat Sep 16 16:26:48 2023 -0700 darwin/arm64 %go test ./... -ldflags='-v=2' 2> >(grep -i 'deadcode: giving up') ? gorm.io/gorm/migrator [no test files] ? gorm.io/gorm/utils/tests [no test files] ok gorm.io/gorm 0.474s ok gorm.io/gorm/callbacks 0.372s ok gorm.io/gorm/clause 0.605s ok gorm.io/gorm/logger (cached) ok gorm.io/gorm/schema 0.689s ok gorm.io/gorm/utils (cached) % ```
jquirke
added a commit
to jquirke/gorm
that referenced
this issue
Sep 17, 2023
Go 1.22 goes somewhat toward addressing the issue using reflect MethodByName disabling linker deadcode elimination (DCE) and the resultant large increase in binary size because the linker cannot prune unused code because it might be reached via reflection. Go Issue golang/go#62257 reduces the number of incidences of this problem by leveraging a compiler assist to avoid marking functions containing calls to MethodByName as ReflectMethods as long as the arguments are constants. An analysis of Uber Technologies code base however shows that a number of transitive imports still contain calls to MethodByName with a variable argument, including GORM. In the case of GORM, the solution we are proposing is because the number of possible methods is finite, we will "unroll" this. This demonstrably shows that GORM is not longer a problem for DCE. Before ``` % go version go version devel go1.22-2f3458a8ce Sat Sep 16 16:26:48 2023 -0700 darwin/arm64 % go test ./... -ldflags='-v=2' 2> >(grep -i 'deadcode: giving up') deadcode: giving up on static analysis due to relect method symbol gorm.io/gorm/schema.ParseWithSpecialTableName<3938> deadcode: giving up on static analysis due to relect method symbol reflect.(*Value).Method<119948> deadcode: giving up on static analysis due to relect method symbol reflect.(*Value).MethodByName<119949> deadcode: giving up on static analysis due to relect method symbol gorm.io/gorm/schema.ParseWithSpecialTableName<49693> deadcode: giving up on static analysis due to relect method symbol reflect.(*Value).Method<117898> deadcode: giving up on static analysis due to relect method symbol reflect.(*Value).MethodByName<117899> deadcode: giving up on static analysis due to relect method symbol gorm.io/gorm/schema.ParseWithSpecialTableName<54029> deadcode: giving up on static analysis due to relect method symbol reflect.(*Value).Method<117635> deadcode: giving up on static analysis due to relect method symbol reflect.(*Value).MethodByName<117636> ok gorm.io/gorm (cached) ok gorm.io/gorm/callbacks (cached) ? gorm.io/gorm/migrator [no test files] ok gorm.io/gorm/clause (cached) ok gorm.io/gorm/logger (cached) ? gorm.io/gorm/utils/tests [no test files] ok gorm.io/gorm/schema (cached) ok gorm.io/gorm/utils (cached) % ``` After ``` % go version go version devel go1.22-2f3458a8ce Sat Sep 16 16:26:48 2023 -0700 darwin/arm64 %go test ./... -ldflags='-v=2' 2> >(grep -i 'deadcode: giving up') ? gorm.io/gorm/migrator [no test files] ? gorm.io/gorm/utils/tests [no test files] ok gorm.io/gorm 0.474s ok gorm.io/gorm/callbacks 0.372s ok gorm.io/gorm/clause 0.605s ok gorm.io/gorm/logger (cached) ok gorm.io/gorm/schema 0.689s ok gorm.io/gorm/utils (cached) % ```
jquirke
added a commit
to jquirke/go
that referenced
this issue
Sep 18, 2023
In deadcode removal in the linker, use of reflect.Type.Method/MethodByName result in an increased number of reachability of false positives of assumed reachable code, due to the intractability of knowing what methods might be used. In golang#62257 there was some compiler assisted improvement added to special case MethodByName and Method with constant arguments, and avoid marking those as AttrReflectMethod. At Uber this optimisation has resulted in smaller binary sizes when the the usage of reflect.Type.Method/ByName had constant arguments. However, there are still a number of less trivial cases which we would like to easily identify in our codebase, and logging would be helpful here.
jquirke
added a commit
to jquirke/go
that referenced
this issue
Sep 18, 2023
In deadcode removal in the linker, use of reflect.Type.Method/MethodByName result in an increased number of reachability of false positives of assumed reachable code, due to the intractability of knowing what methods might be used. In golang#62257 there was some compiler assisted improvement added to special case MethodByName and Method with constant arguments, and avoid marking those as AttrReflectMethod. At Uber this optimisation has resulted in smaller binary sizes when the the usage of reflect.Type.Method/ByName had constant arguments. However, there are still a number of less trivial cases which we would like to easily identify in our codebase, and logging would be helpful here.
jquirke
added a commit
to jquirke/go
that referenced
this issue
Sep 18, 2023
In deadcode removal in the linker, use of reflect.Type.Method/MethodByName result in an increased number of reachability of false positives of assumed reachable code, due to the intractability of knowing what methods might be used. In golang#62257 there was some compiler assisted improvement added to special case MethodByName and Method with constant arguments, and avoid marking those as AttrReflectMethod. At Uber this optimisation has resulted in smaller binary sizes when the the usage of reflect.Type.Method/ByName had constant arguments. However, there are still a number of less trivial cases which we would like to easily identify in our codebase, and logging would be helpful here.
jquirke
added a commit
to jquirke/go
that referenced
this issue
Sep 18, 2023
In deadcode removal in the linker, any use of reflect.Type.Method/MethodByName result in an increased amount of incorrectly assumed reachable code (specifically methods), due to the intractability of knowing what methods might be used. In golang#62257 there was some compiler assisted improvement added to special case MethodByName and Method with constant arguments, and avoid marking those as AttrReflectMethod. At Uber this optimisation has resulted in smaller binary sizes when the the usage of reflect.Type.Method/ByName had constant arguments. However, there are still a number of less trivial cases which we would like to easily identify in our codebase, and logging would be helpful here.
jquirke
added a commit
to jquirke/gorm
that referenced
this issue
Sep 19, 2023
Go 1.22 goes somewhat toward addressing the issue using reflect MethodByName disabling linker deadcode elimination (DCE) and the resultant large increase in binary size because the linker cannot prune unused code because it might be reached via reflection. Go Issue golang/go#62257 reduces the number of incidences of this problem by leveraging a compiler assist to avoid marking functions containing calls to MethodByName as ReflectMethods as long as the arguments are constants. An analysis of Uber Technologies code base however shows that a number of transitive imports still contain calls to MethodByName with a variable argument, including GORM. In the case of GORM, the solution we are proposing is because the number of possible methods is finite, we will "unroll" this. This demonstrably shows that GORM is not longer a problem for DCE. Before ``` % go version go version devel go1.22-2f3458a8ce Sat Sep 16 16:26:48 2023 -0700 darwin/arm64 % go test ./... -ldflags=-dumpdep 2> >(grep -i -e '->.*<reflectmethod>') gorm.io/gorm.(*Statement).BuildCondition -> gorm.io/gorm/schema.ParseWithSpecialTableName <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).Method <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).MethodByName <ReflectMethod> ok gorm.io/gorm (cached) ok gorm.io/gorm/callbacks (cached) gorm.io/gorm/clause_test.BenchmarkComplexSelect -> gorm.io/gorm/schema.ParseWithSpecialTableName <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).Method <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).MethodByName <ReflectMethod> ? gorm.io/gorm/migrator [no test files] ok gorm.io/gorm/clause (cached) ok gorm.io/gorm/logger (cached) gorm.io/gorm/schema_test.TestAdvancedDataTypeValuerAndSetter -> gorm.io/gorm/schema.ParseWithSpecialTableName <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).Method <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).MethodByName <ReflectMethod> ? gorm.io/gorm/utils/tests [no test files] ok gorm.io/gorm/schema (cached) ok gorm.io/gorm/utils (cached) ``` After ``` %go version go version devel go1.22-2f3458a8ce Sat Sep 16 16:26:48 2023 -0700 darwin/arm64 %go test ./... -ldflags=-dumpdep 2> >(grep -i -e '->.*<reflectmethod>') ok gorm.io/gorm (cached) ok gorm.io/gorm/callbacks (cached) ? gorm.io/gorm/migrator [no test files] ? gorm.io/gorm/utils/tests [no test files] ok gorm.io/gorm/clause (cached) ok gorm.io/gorm/logger (cached) ok gorm.io/gorm/schema (cached) ok gorm.io/gorm/utils (cached) ```
jquirke
added a commit
to jquirke/gorm
that referenced
this issue
Sep 19, 2023
Go 1.22 goes somewhat toward addressing the issue using reflect MethodByName disabling linker deadcode elimination (DCE) and the resultant large increase in binary size because the linker cannot prune unused code because it might be reached via reflection. Go Issue golang/go#62257 reduces the number of incidences of this problem by leveraging a compiler assist to avoid marking functions containing calls to MethodByName as ReflectMethods as long as the arguments are constants. An analysis of Uber Technologies code base however shows that a number of transitive imports still contain calls to MethodByName with a variable argument, including GORM. In the case of GORM, the solution we are proposing is because the number of possible methods is finite, we will "unroll" this. This demonstrably shows that GORM is not longer a problem for DCE. Before ``` % go version go version devel go1.22-2f3458a8ce Sat Sep 16 16:26:48 2023 -0700 darwin/arm64 % go test ./... -ldflags=-dumpdep 2> >(grep -i -e '->.*<reflectmethod>') gorm.io/gorm.(*Statement).BuildCondition -> gorm.io/gorm/schema.ParseWithSpecialTableName <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).Method <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).MethodByName <ReflectMethod> ok gorm.io/gorm (cached) ok gorm.io/gorm/callbacks (cached) gorm.io/gorm/clause_test.BenchmarkComplexSelect -> gorm.io/gorm/schema.ParseWithSpecialTableName <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).Method <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).MethodByName <ReflectMethod> ? gorm.io/gorm/migrator [no test files] ok gorm.io/gorm/clause (cached) ok gorm.io/gorm/logger (cached) gorm.io/gorm/schema_test.TestAdvancedDataTypeValuerAndSetter -> gorm.io/gorm/schema.ParseWithSpecialTableName <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).Method <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).MethodByName <ReflectMethod> ? gorm.io/gorm/utils/tests [no test files] ok gorm.io/gorm/schema (cached) ok gorm.io/gorm/utils (cached) ``` After ``` %go version go version devel go1.22-2f3458a8ce Sat Sep 16 16:26:48 2023 -0700 darwin/arm64 %go test ./... -ldflags=-dumpdep 2> >(grep -i -e '->.*<reflectmethod>') ok gorm.io/gorm (cached) ok gorm.io/gorm/callbacks (cached) ? gorm.io/gorm/migrator [no test files] ? gorm.io/gorm/utils/tests [no test files] ok gorm.io/gorm/clause (cached) ok gorm.io/gorm/logger (cached) ok gorm.io/gorm/schema (cached) ok gorm.io/gorm/utils (cached) ```
jquirke
added a commit
to jquirke/gorm
that referenced
this issue
Sep 19, 2023
Go 1.22 goes somewhat toward addressing the issue using reflect MethodByName disabling linker deadcode elimination (DCE) and the resultant large increase in binary size because the linker cannot prune unused code because it might be reached via reflection. Go Issue golang/go#62257 reduces the number of incidences of this problem by leveraging a compiler assist to avoid marking functions containing calls to MethodByName as ReflectMethods as long as the arguments are constants. An analysis of Uber Technologies code base however shows that a number of transitive imports still contain calls to MethodByName with a variable argument, including GORM. In the case of GORM, the solution we are proposing is because the number of possible methods is finite, we will "unroll" this. This demonstrably shows that GORM is not longer a problem for DCE. Before ``` % go version go version devel go1.22-2f3458a8ce Sat Sep 16 16:26:48 2023 -0700 darwin/arm64 % go test ./... -ldflags=-dumpdep 2> >(grep -i -e '->.*<reflectmethod>') gorm.io/gorm.(*Statement).BuildCondition -> gorm.io/gorm/schema.ParseWithSpecialTableName <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).Method <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).MethodByName <ReflectMethod> ok gorm.io/gorm (cached) ok gorm.io/gorm/callbacks (cached) gorm.io/gorm/clause_test.BenchmarkComplexSelect -> gorm.io/gorm/schema.ParseWithSpecialTableName <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).Method <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).MethodByName <ReflectMethod> ? gorm.io/gorm/migrator [no test files] ok gorm.io/gorm/clause (cached) ok gorm.io/gorm/logger (cached) gorm.io/gorm/schema_test.TestAdvancedDataTypeValuerAndSetter -> gorm.io/gorm/schema.ParseWithSpecialTableName <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).Method <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).MethodByName <ReflectMethod> ? gorm.io/gorm/utils/tests [no test files] ok gorm.io/gorm/schema (cached) ok gorm.io/gorm/utils (cached) ``` After ``` %go version go version devel go1.22-2f3458a8ce Sat Sep 16 16:26:48 2023 -0700 darwin/arm64 %go test ./... -ldflags=-dumpdep 2> >(grep -i -e '->.*<reflectmethod>') ok gorm.io/gorm (cached) ok gorm.io/gorm/callbacks (cached) ? gorm.io/gorm/migrator [no test files] ? gorm.io/gorm/utils/tests [no test files] ok gorm.io/gorm/clause (cached) ok gorm.io/gorm/logger (cached) ok gorm.io/gorm/schema (cached) ok gorm.io/gorm/utils (cached) ```
jquirke
added a commit
to jquirke/gorm
that referenced
this issue
Sep 19, 2023
Go 1.22 goes somewhat toward addressing the issue using reflect MethodByName disabling linker deadcode elimination (DCE) and the resultant large increase in binary size because the linker cannot prune unused code because it might be reached via reflection. Go Issue golang/go#62257 reduces the number of incidences of this problem by leveraging a compiler assist to avoid marking functions containing calls to MethodByName as ReflectMethods as long as the arguments are constants. An analysis of Uber Technologies code base however shows that a number of transitive imports still contain calls to MethodByName with a variable argument, including GORM. In the case of GORM, the solution we are proposing is because the number of possible methods is finite, we will "unroll" this. This demonstrably shows that GORM is not longer a problem for DCE. Before ``` % go version go version devel go1.22-2f3458a8ce Sat Sep 16 16:26:48 2023 -0700 darwin/arm64 % go test ./... -ldflags=-dumpdep 2> >(grep -i -e '->.*<reflectmethod>') gorm.io/gorm.(*Statement).BuildCondition -> gorm.io/gorm/schema.ParseWithSpecialTableName <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).Method <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).MethodByName <ReflectMethod> ok gorm.io/gorm (cached) ok gorm.io/gorm/callbacks (cached) gorm.io/gorm/clause_test.BenchmarkComplexSelect -> gorm.io/gorm/schema.ParseWithSpecialTableName <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).Method <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).MethodByName <ReflectMethod> ? gorm.io/gorm/migrator [no test files] ok gorm.io/gorm/clause (cached) ok gorm.io/gorm/logger (cached) gorm.io/gorm/schema_test.TestAdvancedDataTypeValuerAndSetter -> gorm.io/gorm/schema.ParseWithSpecialTableName <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).Method <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).MethodByName <ReflectMethod> ? gorm.io/gorm/utils/tests [no test files] ok gorm.io/gorm/schema (cached) ok gorm.io/gorm/utils (cached) ``` After ``` %go version go version devel go1.22-2f3458a8ce Sat Sep 16 16:26:48 2023 -0700 darwin/arm64 %go test ./... -ldflags=-dumpdep 2> >(grep -i -e '->.*<reflectmethod>') ok gorm.io/gorm (cached) ok gorm.io/gorm/callbacks (cached) ? gorm.io/gorm/migrator [no test files] ? gorm.io/gorm/utils/tests [no test files] ok gorm.io/gorm/clause (cached) ok gorm.io/gorm/logger (cached) ok gorm.io/gorm/schema (cached) ok gorm.io/gorm/utils (cached) ```
jquirke
added a commit
to jquirke/gorm
that referenced
this issue
Sep 19, 2023
Go 1.22 goes somewhat toward addressing the issue using reflect MethodByName disabling linker deadcode elimination (DCE) and the resultant large increase in binary size because the linker cannot prune unused code because it might be reached via reflection. Go Issue golang/go#62257 reduces the number of incidences of this problem by leveraging a compiler assist to avoid marking functions containing calls to MethodByName as ReflectMethods as long as the arguments are constants. An analysis of Uber Technologies code base however shows that a number of transitive imports still contain calls to MethodByName with a variable argument, including GORM. In the case of GORM, the solution we are proposing is because the number of possible methods is finite, we will "unroll" this. This demonstrably shows that GORM is not longer a problem for DCE. Before ``` % go version go version devel go1.22-2f3458a8ce Sat Sep 16 16:26:48 2023 -0700 darwin/arm64 % go test ./... -ldflags=-dumpdep 2> >(grep -i -e '->.*<reflectmethod>') gorm.io/gorm.(*Statement).BuildCondition -> gorm.io/gorm/schema.ParseWithSpecialTableName <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).Method <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).MethodByName <ReflectMethod> ok gorm.io/gorm (cached) ok gorm.io/gorm/callbacks (cached) gorm.io/gorm/clause_test.BenchmarkComplexSelect -> gorm.io/gorm/schema.ParseWithSpecialTableName <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).Method <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).MethodByName <ReflectMethod> ? gorm.io/gorm/migrator [no test files] ok gorm.io/gorm/clause (cached) ok gorm.io/gorm/logger (cached) gorm.io/gorm/schema_test.TestAdvancedDataTypeValuerAndSetter -> gorm.io/gorm/schema.ParseWithSpecialTableName <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).Method <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).MethodByName <ReflectMethod> ? gorm.io/gorm/utils/tests [no test files] ok gorm.io/gorm/schema (cached) ok gorm.io/gorm/utils (cached) ``` After ``` %go version go version devel go1.22-2f3458a8ce Sat Sep 16 16:26:48 2023 -0700 darwin/arm64 %go test ./... -ldflags=-dumpdep 2> >(grep -i -e '->.*<reflectmethod>') ok gorm.io/gorm (cached) ok gorm.io/gorm/callbacks (cached) ? gorm.io/gorm/migrator [no test files] ? gorm.io/gorm/utils/tests [no test files] ok gorm.io/gorm/clause (cached) ok gorm.io/gorm/logger (cached) ok gorm.io/gorm/schema (cached) ok gorm.io/gorm/utils (cached) ```
jinzhu
pushed a commit
to go-gorm/gorm
that referenced
this issue
Oct 10, 2023
Go 1.22 goes somewhat toward addressing the issue using reflect MethodByName disabling linker deadcode elimination (DCE) and the resultant large increase in binary size because the linker cannot prune unused code because it might be reached via reflection. Go Issue golang/go#62257 reduces the number of incidences of this problem by leveraging a compiler assist to avoid marking functions containing calls to MethodByName as ReflectMethods as long as the arguments are constants. An analysis of Uber Technologies code base however shows that a number of transitive imports still contain calls to MethodByName with a variable argument, including GORM. In the case of GORM, the solution we are proposing is because the number of possible methods is finite, we will "unroll" this. This demonstrably shows that GORM is not longer a problem for DCE. Before ``` % go version go version devel go1.22-2f3458a8ce Sat Sep 16 16:26:48 2023 -0700 darwin/arm64 % go test ./... -ldflags=-dumpdep 2> >(grep -i -e '->.*<reflectmethod>') gorm.io/gorm.(*Statement).BuildCondition -> gorm.io/gorm/schema.ParseWithSpecialTableName <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).Method <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).MethodByName <ReflectMethod> ok gorm.io/gorm (cached) ok gorm.io/gorm/callbacks (cached) gorm.io/gorm/clause_test.BenchmarkComplexSelect -> gorm.io/gorm/schema.ParseWithSpecialTableName <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).Method <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).MethodByName <ReflectMethod> ? gorm.io/gorm/migrator [no test files] ok gorm.io/gorm/clause (cached) ok gorm.io/gorm/logger (cached) gorm.io/gorm/schema_test.TestAdvancedDataTypeValuerAndSetter -> gorm.io/gorm/schema.ParseWithSpecialTableName <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).Method <ReflectMethod> type:reflect.Value <UsedInIface> -> reflect.(*Value).MethodByName <ReflectMethod> ? gorm.io/gorm/utils/tests [no test files] ok gorm.io/gorm/schema (cached) ok gorm.io/gorm/utils (cached) ``` After ``` %go version go version devel go1.22-2f3458a8ce Sat Sep 16 16:26:48 2023 -0700 darwin/arm64 %go test ./... -ldflags=-dumpdep 2> >(grep -i -e '->.*<reflectmethod>') ok gorm.io/gorm (cached) ok gorm.io/gorm/callbacks (cached) ? gorm.io/gorm/migrator [no test files] ? gorm.io/gorm/utils/tests [no test files] ok gorm.io/gorm/clause (cached) ok gorm.io/gorm/logger (cached) ok gorm.io/gorm/schema (cached) ok gorm.io/gorm/utils (cached) ```
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Labels
binary-size
compiler/runtime
Issues related to the Go compiler and/or runtime.
FrozenDueToAge
NeedsFix
The path to resolution is known, but the work has not been done.
Normally, a call to
MethodByName()
disables the DCE because the linker assumes that any method can be accessed this way. This pessimises the code generation fork8s.io/apimachinery
which needsMethodByName()
to verify whether or not a struct implementsDeepCopyInto()
. It cannot cast a struct tointerface { DeepCopyInto() Foo }
because the return type may vary. Instead, it does the following:In this case there is no need to disable the DCE altogether. It suffices to add a relocation to keep methods named
DeepCopyInto()
.The text was updated successfully, but these errors were encountered: