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

[NETBEANS-6077] Cached Transformation Classloader, based on set of classpath roots. #3213

Merged
merged 4 commits into from
Oct 8, 2021

Conversation

sdedic
Copy link
Member

@sdedic sdedic commented Oct 5, 2021

Groovy parser creates two class loaders - as Groovy compiler uses ClassLoader API to reach out for resources in the user project and/or libraries:

  • ParsingClassLoader, which should serve files from user project, sources etc. It is used for symbol or resource resolution.
  • TransformationClassLoader whose job is to load extensions to the Groovy Compiler, visitors and transformers.

The distinction is that while the user project's content may change (user rewrites some files, adds or removes some from the project), so contents of Parsing Classloader should be thrown away, the classes loaded by Transformation ClassLoader are not intended to be part of user project, rather they become part of the IDE runtime.

So far, those classes are loaded to JVM during each parse request - performing all startup linking, verification - AND initialization. It's less visible during indexing, as the whole root is indexed using one set of classloaders, but has big impact on ad hoc parsing tasks like code completion, refrence search, semantic highlight etc.

The issue is highly visible on projects that use sophisticated libraries that add Groovy transformation visitors - which are likely to use its library classes so they are incorporated into IDE's runtime (and then thrown away).

This PR creates a classloader cache for the Transformation classloader. The cache is local to a project, so the contents eventually vanishes after the project closes. One instance of the cache is global to cover files that do not belong to any project. The cache is size-bound and expires (TimedSoftReference) its content after ~30 sec of inactivity (provided the classloader is not referenced from anywhere).
The cached classloader monitors set of roots of the ClassPath it was created for; if the set of roots changes, the classloader invalidates itself - a new one will be created on next parse request. The validation is also done during parsing startup, so the parser should always start with a consistent state.

The speedup for completion is again on scale of a magnitude: instead of ~10-12 seconds (micronaut-core project), the completion now appears after about 0.5-2 secs.

Copy link

@JaroslavTulach JaroslavTulach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Internal changes in groovy are fine. I don't understand (and agree to) the change in friend module list. I don't understand the change in java modules.

@JaroslavTulach JaroslavTulach self-requested a review October 6, 2021 08:30
Copy link
Contributor

@dbalek dbalek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks fine.

@sdedic
Copy link
Member Author

sdedic commented Oct 6, 2021

Reviewer feedback incorporated (8defbe9); bugfixes split as separate commits (1a76ec2, df8add2).

@sdedic sdedic merged commit 058f42a into apache:master Oct 8, 2021
@ebarboni ebarboni added this to the 12.6 milestone Oct 11, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants