-
Notifications
You must be signed in to change notification settings - Fork 17.9k
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
proposal: text/template,html/template: Template.ExecuteLite skip resolution to methods to allow DCE #72895
Comments
cc @robpike |
Related Issues
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.) |
I never liked APIs designed to work around toolchain problems. They are a category error. |
It can also be considered as a safe API which won't have any unexpected side effects from executing code. maybe naming it |
|
We try to avoid such APIs so I don't know that there are many examples in the standard library. I don't see the comparison to RPCs as particularly relevant. RPCs have an inherent cost, as you say. That cost doesn't have anything to do with tooling, it's part of the definition of RPCs. What we're talking about here is that the linker has a particular optimization in which it removes unreferenced methods. When some standard library calls are used, that optimization is invalid, so it isn't performed. None of this is inherent to the way that methods are used in Go. It's just a specific implementation of a specific optimization in the linker. The argument that you are making is in some ways an argument against making this kind of optimization at all. Optimizations that have a surprising performance cliff are confusing for users. In the discussion of the CL that added this linker optimization, https://go.dev/cl/20483, text/template came up and it seems that people decided that the optimization was worth doing anyhow for small utility programs. It seems unfortunate to use that to say that now the optimization applies to large programs so we have to figure out a way to complicate templates. It seems like a valid alternative is to say that the optimization only applies to small utility programs. |
By the way, I don't think the security argument is all that strong, because in my experience most code passes a customized type to text/template. That type has whatever methods are needed, and generally nothing else. Also, of course, most code does not use user input as a template. That said, that does point the way to a different approach. The compiler/linker can record calls to This is, of course, a significant special case for the standard library. But all of this code is already a special case. From a quick look, text/template is the only standard library package that calls |
It's hard to show with just a github search but quite often I see I think that nested but maybe that's better if method use in templates are really common. Also hard to search for, and we don't encourage getters but: https://github.com/search?q=%2F%5C%7B%5C%7B.*+%5C.Get.*%5C%7D%5C%7D%2F&type=code&p=1 I did propose this as I also saw this was the only stdlib api that used MethodByName |
Since you can chain field invocations, then also (recursively)
|
We don't have to solve every existing case, we just have to provide a clear path forward for people who actually care about this. After all, |
Are you suggesting that the "retained" guarantee does not extend on chained methods? I assumed correctness is not negotiable. |
@seankhliao wrote:
To be fair, you might find yourself promulgating it into html/template's |
I was trying to find an example where we let the imperfect characteristics of an underlying platform shape the APIs. The difference here is that networks started imperfect and got more reliable with time, while reflection started off reliable and since then been threatened by mavericks attempting to skirt safety regulations ;)
Yes, and even if we made it easier to diagnose (a few proposals were made, but so far only https://github.com/aarzilli/whydeadcode offers a practical tool), the cliff-y nature is inherently confusing. While we might've never known this optimization, now we've tasted the forbidden fruit so to speak: I've seen a 200MB binary reduced to 100MB, seen build times slashed in half (for huge monolith packages, the kind you get with some big corp SDKs). Users in charge of efficiency and developer experience especially in large companies would have a unique interest in impactful optimizations of this kind, in a way that sets them apart from regular users. It might be possible to keep both crowds happy, though of course the regular users are the important long tail for the ecosystem's success. It can also be argued that large packages (either by themselves or through a widely cast network of imports) are what those efficiency-seekers should be after. I'm not sure how practical this approach is, but it might be. |
I don't feel that a compiler special case would be particularly clear to program authors. You can't really write a test or linter that ensures the property (presumably if you care enough for this property, you want it to continue to hold in the future). It does have the benefit that maybe more programs will immediately benefit if their data args happen to fit the criteria.
|
No, you're quite right about that. I was responding to an earlier comment.
But we can see that the existing compiler special case is also not particularly clear. Adding |
Proposal Details
Use of reflect.Value.Method or reflect.Value.MethodByName disables dead code elimination in the linker as it cannot know needs to kept around vs what can be dropped.
text/template
and by extensionhtml/template
are perhaps the main paths through which these methods become reachable in programs written in Go.This leads to issues like:
I assert that many using of text/template only need to operate on static data (precomputed struct fields, maps, slices).
A new method for template execution that skips attempting to resolve arguments to methods could work for a majority of users while still enabling DCE.
The text was updated successfully, but these errors were encountered: