-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Is maxstack really necessary? #62913
Comments
I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label. |
THis seems reasonable to me. Though i imagine another suitable approach would be to have a helper that can compute this at compile time and just embed the appropriate stack depth so that the jit doesn't have to do this work. That would potentially be a best-of-both worlds approach (IMO at least) whereby the burden is eased on the metadata-emitter, and the cost is not paid at runtime by the JIT. @jkotas any thoughts here? |
If this were to happen in System.Reflection.Metadata.Ecma355, (the natural place to put such a helper in the Runtime libraries,) the ideal place to include such code would be under the hood of Putting it someplace external would violate DRY and significantly increase complexity by requiring consumers of the API to track the history of the opcodes they encode externally. It could conceivably be placed in a helper class somewhere to help people working on other metadata systems, but realistically speaking the benefit of doing so would be minimal because such an analyzer needs to work on some representation of IL opcodes and streams, and other metadata systems are unlikely to use the one provided by SRM. (Though perhaps there would be benefit in a helper class for analysis purposes when using SRM to read/edit an assembly. Either way, it should still be invoked under the hood of |
The highly sophisticated modern JITs are not the only components that consume IL. For example, there are number of interpreters out there. Some of them take advantage of maxstack to preallocate its internal data structures. Also, JIT inliner uses maxstack as one of the early outs to reject inlining candidates that are likely too complex. You can use some sort of conversative estimate for maxstack. Number of components out there do that, with the caveat that it may behave poorly in some situations. Adding a helper to |
Tagging subscribers to this area: @dotnet/area-system-reflection-metadata Issue DetailsOne of the trickier parts of creating IL metadata is figuring out the correct value for
I'm sure that made sense in 2012, but a lot has changed since then. With every new .NET release, we're treated to blog posts explaining the advances that have been made both in the libraries and in the JIT compilers to improve performance. A conservative estimate of the While actually removing this from the metadata would be infeasible due to backwards compatibility, it seems reasonable to make it something optional that the JIT ignores, either unconditionally or if told to (perhaps if you specify a value of -1?) so as to ease the burden on compiler developers. Any thoughts on this?
|
That would be nice if it can be done, particularly if it can be done efficiently. Does a general-case algorithm exist for computing the precise max stack requirement from an IL stream? I haven't looked deeply into this, but it intuitively feels like beating the conservative estimate provided by the refemit running-total algorithm is something that could be done in specific cases by a human observer, but not something that would be easy to do algorithmically for all cases. |
I believe that the algorithm to compute precise max stack can be linear with the size of IL stream. So the efficiency is just about the constant multiplier. Note that If we were to add the helper for |
If I might ask, what's the purpose of creating an API for compiler writers that you expect compiler writers will never actually use, and would in fact prefer to go to all the effort of rolling their own despite the fact that a prebuilt solution exists? |
This API would be for people who use I agree with you that it is debatable to be adding APIs that only work well for trivial cases. The same can be said about |
Perhaps it did at one point? dotnet/corefx#5354 |
@jkotas So A metadata writer library needs an IL emitter. So as long as we're throwing ideas around, how would you fix it? Changes to the implementation? A new class and deprecate the old one? Move Roslyn's much better IL emitter into SRM.Ecma335? |
@ericstj I'm sorry, perhaps what did what at some point? |
I updated my comment. Perhaps Roslyn was using |
The expectation is that a S.R.Metadata user has a type system thing running next to S.R.Metadata that can answer these questions. An API addition to compute MaxStack in |
@MichalStrehovsky You're right, that does tend to complicate things. Personally I'd prefer to resolve this with a system that requires all tokens to be declared, and their basic shape defined, before they can be used, but does not require a token's underlying data to be complete before it can be declared. But that's essentially the exact opposite of how SRM works. So my idea won't work without some kind of callback setup for the calculation code to query the library consumer's "type system thing" for information, and that could balloon into a big, ugly mess of complexity very quickly. Do you have any preferred alternatives for how to implement something like this? |
I think that code emitters in serious compilers typically up being highly opinionated APIs to make them fit well with the rest of the compiler. It is hard to create a great non-opinionated code emitter API in isolation. Both If somebody came with .NET compiler construction framework (something like LLVM for .NET), it would make sense to have IL code emitter as part of it that fits well with the rest of the framework. I can believe that the code emitter like that would work well for serious work and nobody using that framework would think twice about using it. |
Well, I've never looked too closely at its efficiency, but honestly I don't see much in the way of usability problems with |
S.R.Metadata tends to do these callbacks through generics so this would probably be something along the lines of If you're looking for inspiration on how to do this as a post pass in a precise fashion, this might be useful:
|
I think you could pass a delegate |
Closing as answered. |
One of the trickier parts of creating IL metadata is figuring out the correct value for
maxstack
for a method, especially now that refemit is no longer available to do it for you if you want to be able to save the result. According to the CIL standard , III.1.7.4,maxstack
must be provided and it must not be smaller than the actual maximum IL execution stack size of a method. The rationale given is:I'm sure that made sense in 2012, but a lot has changed since then. With every new .NET release, we're treated to blog posts explaining the advances that have been made both in the libraries and in the JIT compilers to improve performance. A conservative estimate of the
maxstack
value can be easily calculated by a single-pass analysis of an IL opcode stream (have a look at how refemit does it), so it seems a bit redundant for a highly sophisticated modern JIT to require as input information that it could trivially compute for itself.While actually removing this from the metadata would be infeasible due to backwards compatibility, it seems reasonable to make it something optional that the JIT ignores, either unconditionally or if told to (perhaps if you specify a value of -1?) so as to ease the burden on compiler developers.
Any thoughts on this?
The text was updated successfully, but these errors were encountered: