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

define Core.Closure and make compiler-generated closures subtype of it #56928

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

aviatesk
Copy link
Member

@aviatesk aviatesk commented Jan 1, 2025

Performance issues related to code containing closures are frequently discussed (e.g., #15276, #56561). Several approaches can be considered to address this problem, one of which involves re-inferring code containing closures (#56687). To implement this idea, it is necessary to determine whether a given piece of code includes a closure. However, there is currently no explicit mechanism for making this determination (although there are some code that checks whether the function name contains "#" for this purpose, but this is an ad hoc solution).

To address this, this commit lays the foundation for future optimizations targeting closures by defining closure functions as a subtype of the new type Core.Closure <: Function. This change allows the optimizer to apply targeted optimizations to code containing calls to functions that are subtype of Core.Closure.

Performance issues related to code containing closures are frequently
discussed (e.g., #15276, #56561). Several
approaches can be considered to address this problem, one of which
involves re-inferring code containing closures (#56687).
To implement this idea, it is necessary to determine whether a given
piece of code includes a closure. However, there is currently no
explicit mechanism for making this determination (although there are
some code that checks whether the function name contains `"#"` for this
purpose, but this is an ad hoc solution).

To address this, this commit lays the foundation for future
optimizations targeting closures by defining closure functions as a
subtype of the new type `Core.Closure <: Function`. This change allows
the optimizer to apply targeted optimizations to code containing calls
to functions that are subtype of `Core.Closure`.
@aviatesk aviatesk requested a review from JeffBezanson January 1, 2025 09:30
@Seelengrab
Copy link
Contributor

Is it possible to disallow manual subtyping of Core.Closure?

@nsajko
Copy link
Contributor

nsajko commented Jan 1, 2025

To implement this idea, it is necessary to determine whether a given piece of code includes a closure.

As far as I understand, the initial idea with #56687 was to apply post-optimization inference to all code, but now this is being restricted to merely the compiler-generated closures. May I ask why, out of curiosity?

@aviatesk
Copy link
Member Author

aviatesk commented Jan 2, 2025

Is it possible to disallow manual subtyping of Core.Closure?

It might be possible, but what is the purpose of doing so?

To implement this idea, it is necessary to determine whether a given piece of code includes a closure.

As far as I understand, the initial idea with #56687 was to apply post-optimization inference to all code, but now this is being restricted to merely the compiler-generated closures. May I ask why, out of curiosity?

The re-inference implemented in #56687 can be applied to any code but is not executed for all code. It is only performed when the optimizer could derive new type information. For code containing closures, this typically requires either inlining the closure or performing inter-procedural alias analysis. In any case, applying re-inference to all code would incur significant latency costs, so it must be performed selectively.

@Seelengrab
Copy link
Contributor

It might be possible, but what is the purpose of doing so?

If the type is intended as a surefire way for the compiler to know that the closure object came from itself earlier in the compilation pipeline, i.e. that instances of it uphold the invariants concrete subtypes of Core.Closure are expected to establish, disallowing manual subtyping prevents those invariants from breaking due to wrong usage.

@vtjnash
Copy link
Member

vtjnash commented Jan 2, 2025

What is the expected benefit of this, over the existing definition of a closure: !jl_is_datatype_singleton (julia !issingletontype) && jl_static_is_function_ (julia <:(Function))?

@vtjnash
Copy link
Member

vtjnash commented Jan 2, 2025

uphold the invariants concrete subtypes of Core.Closure are expected to establish

There are no limits on what a Core.Closure can do; they are normal structs created by syntactic transform.

@aviatesk
Copy link
Member Author

aviatesk commented Jan 3, 2025

What is the expected benefit of this, over the existing definition of a closure: !jl_is_datatype_singleton (julia !issingletontype) && jl_static_is_function_ (julia <:(Function))?

I would like to apply a special inline cost to closures to enable aggressive SROA and optimize away closure constructs. And the existing definition applies to all functors, but the issue I aim to address is specific to the compiler-generated closures. ft <: Core.Closure is more accurate and convenient for this purpose.

@Seelengrab
Copy link
Contributor

There are no limits on what a Core.Closure can do; they are normal structs created by syntactic transform.

I'm not talking about what a closure can do in the computational sense. I understand that Core.Closure is intended as "normal structs" originating from lowering. I'm talking about what this specific subtyping implies semantically and what sorts of properties are assumed true.

For example, is it allowed to define primitive type Foo <: Core.Closure 8 end as a user? This would break the invariant/assumption that all subtypes of Core.Closure are structs, for example, and presumably crash on some other assumptions the compiler would make, such as existence of specific fields etc. From what I gather, it doesn't make a whole lot of sense to have users manually define subtypes for Core.Closure without going through lowering, especially if subtypes of that type would get some specialized optimizations applied to them. Hence my question whether it makes sense to allow manual subtyping there in the first place.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants