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

Explore how to pre-compile SpEL expressions during AOT processing #29548

Open
sdeleuze opened this issue Nov 22, 2022 · 1 comment
Open

Explore how to pre-compile SpEL expressions during AOT processing #29548

sdeleuze opened this issue Nov 22, 2022 · 1 comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) theme: aot An issue related to Ahead-of-time processing

Comments

@sdeleuze
Copy link
Contributor

The purpose of this issue is to explore if it is possible to remove SpEL implementation from the reachable code path by performing an AOT processing of SpEL expressions to generate related bytecode at build-time, and introduce a dedicated BeanExpressionResolver used in AOT mode without a dependency on StandardBeanExpressionResolver with 3 goals:

  • Reduce the number of hints required at runtime on native due to SpEL reflection usage
  • Avoid loading most of the SpEL infrastructure by default for optimization purpose
  • Perform SpEL to bytecode generation at build-time to skip that processing at runtime

Pre-processing of SpEL expressions in annotations like Spring Framework @Value or Spring Security @PreAuthorize / @PostAuthorize / @PreFilter / @PostFilter (cc @rwinch) would be the main use cases, but other potential use cases of BeanExpressionResolver should be explored to ensure the feasibility of this optimization.

Usage of SpEL in Thymeleaf would be probably out of the scope, or would require build-time compilation of Thymeleaf templates which is out of the scope of this issue, even if that's an interesting idea.

@sbrannen
Copy link
Member

sbrannen commented Mar 20, 2024

Perform SpEL to bytecode generation at build-time to skip that processing at runtime

I've put some thought into this, and I'll share my findings here.

The first challenge is saving the compiled bytecode to .class files.

Luckily, we already have a prototype for that.

At the end of the SpelCompiler.createExpressionClass(SpelNodeImpl) method, there's a commented-out invocation of saveGeneratedClassFile(expressionToCompile.toStringAST(), className, data).

A simple implementation of that exists in SpelCompilationCoverageTests.

Using that and running a SpEL compilation test currently generates files such as build/spel.Ex2.class. We'd probably want to rename the package from spel to something like org.springframework.expression.spel.compiled. And we'd need to come up with unique class names that can be mapped to the expression.

So, compiling the expressions and saving the generated byte code to disk should be achievable tasks.

The main challenges that I foresee are:

  • Mapping each expression to a unique ID (unique generated class name), depending on the context in which the expression is used, potentially dependent on the ClassLoader used to compile the expression, etc.
  • Eager evaluation of each expression, and eager evaluation of all branches of the expression if applicable.

The latter is necessary to successfully compile a SpEL expression. For example, a simple ternary expression such as #list.isEmpty() ? -1 : #list.size() cannot be compiled unless both branches are evaluated. This means that such an expression must be evaluated twice: once with isEmpty() returning true and one with isEmpty() returning false.

@sbrannen sbrannen changed the title Explore how to make StandardBeanExpressionResolver not reachable in AOT mode Explore how to pre-compile SpEL expressions during AOT processing Mar 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) theme: aot An issue related to Ahead-of-time processing
Projects
None yet
Development

No branches or pull requests

2 participants