-
Notifications
You must be signed in to change notification settings - Fork 18k
text/template: builtins global map impacts dead code elimination #36021
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
Comments
How does lazy initialization help? The linker doesn't care that it's lazily initialized. The link only cares that
That's not true. Only dead code elimination of exported methods. |
@bradfitz if the map is only initalized when it's first used, DCE will only be disabled if the program uses templating functions. the problem that currently using any function from
this is true, but it's still a lot. for u-root, it's 15% of binary size. |
This is arguably a defect in the DCE analysis: if the code to initialize the map only writes to that map (and does not mutate other global state as a side-effect), and no live function reads from the map, then both the map itself and the code to initialize it should be considered dead and eliminated. However, that defect is admittedly not easy to fix in general: it would require DCE to do something akin to escape analysis and/or pure-function detection, and the calls to |
Change https://golang.org/cl/210284 mentions this issue: |
@bradfitz can you please clarify what release your pending CL will be committed to? i see that it didn't make 1.14, so which will it be? |
Go 1.15, August 2020. |
ugh, that's bad news |
Just fork the package and fix meanwhile if you need it. That's an easy workaround which is why we don't rush this in. |
how do you suggest we do that? i tried the most obvious way - via
|
Vendor that too. |
ok, that works, thanks! |
@bradfitz, actually, it doesn't. or rather, no always - it's weird.
simplest test case, main.go:
i have
however, if i import
looks like when importing from standard library a different vendor tree is used. |
Yes, the standard library uses the If you need to patch the standard library, patch the standard library itself (in Or, if you want to substitute |
@bcmills patching standard library is what we're trying to avoid, of course, since it's an inconvenience to users. changing imports is not an option since what gets us to text/template is the indirect dependency via go/build and then go/doc. there just isn't a good way to override even small parts of stdlib, it seems. |
fwiw, https://github.com/rojer/u-root/commit/e84d5ba1d54aa62379c038ff9a153894f3db5b55 is what i got working on 1.13 but it completely explodes on earlier versions and will probably do so with 1.14 as well, making is a nightmare to maintain. |
Wait, how are you ending up with |
after a bunch of other changes, this really is the last thing that is keeping us from saving 3M out of 18. |
…nation Fixes golang#36021 Updates golang#2559 Updates golang#26775 Change-Id: I2e6708691311035b63866f25d5b4b3977a118290 Reviewed-on: https://go-review.googlesource.com/c/go/+/210284 Run-TryBot: Brad Fitzpatrick <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Reviewed-by: Rob Pike <[email protected]>
What version of Go are you using (
go version
)?1.13.5
Does this issue reproduce with the latest release?
yes
The map of builtin functions that can be invoked from templates is defined as a global variable here.
It references the
call
function, which usesreflect.Call
to invoke a user function. This is one of the conditions that disables dead code elimination in the linker.At the moment Go is unable to elide unused global maps - see #31704 and long discussion on #2559.
As a result, if anything imports text/template, even transitively, dead code elimination is disabled for entire program.
Consider this simple program: https://github.com/rojer/go-dce-bug
pkg1.MyStruct.Junk method is unused and should be eliminated. However, as described here, DCE is disabled and it is not eliminated:
The reason is, pkg2 imports
text/template
. the function that references text/template is unused, and even if it were, it does nit use templates as such, just a simple exported function. But since compiler cannot properly elide global map initializers,reflect.Call
ends up being marked reachable viatext/template.builtins
andtext/template.call
.Bottom line is, the
text/template.builtins
map has very high cost to the program and until Go compiler gets better at eliminating unused global variables, its initalization should be removed from package scope and the map should be initialized on first use.The text was updated successfully, but these errors were encountered: