EmmyLua / IntelliJ-EmmyLua

Lua IDE/Debugger Plugin for IntelliJ IDEA
https://emmylua.github.io
Apache License 2.0
1.72k stars 287 forks source link

Fix deadlock in class initializers during indexing #511

Closed Techcable closed 1 year ago

Techcable commented 1 year ago

Fixes issue #510

Looking at the YourKit deadlock info in issue #510, I noticed that one thread was stuck on the class initializer in Ty.<clinit>.

In the JVM, a class can not be used until its class initializer is run. In Java, this requires its static fields to be fully created. In Kotlin, this requires the companion object to be fully created.

It looks like the JVM couldn't finish creating the STRING field in Ty companion object: https://github.com/EmmyLua/IntelliJ-EmmyLua/blob/efb06ef47ca06d14d3cb47a1aa0dc86eabaed4f7/src/main/java/com/tang/intellij/lua/ty/Ty.kt#L198

It turns out that constructing TyPrimitiveClass requires the Ty class. The JVM can't construct a TyPrimitiveClass until it has the Ty class, and it can't construct the 'Ty class until it created the STRING field.

So the JVM deadlocks and IntelliJ freezes during indexing.

It looks like the jstack command also alluded to this issue. It shows the following when I query the stalled IntelliJ process: waiting on the Class initialization monitor for com.tang.intellij.lua.ty.Ty

To fix this deadlock, I used Kotlin 'lazy' properties.

This means the constructor will only be called when the STRING field is first accessed.

I tested the result in IntelliJ, and that specific problem went away.

However, I saw a similar deadlock problem for TyClass. The TyClass initializer calls createSerializedObject in its companion object:

https://github.com/EmmyLua/IntelliJ-EmmyLua/blob/efb06ef47ca06d14d3cb47a1aa0dc86eabaed4f7/src/main/java/com/tang/intellij/lua/ty/TyClass.kt#L185

However, running createSerializedObject needs TyClass to work, creating another deadlock.

Once again, I used a lazy property. This finally fixed the deadlocks! Now IntelliJ indexes the Lua code, and I can access completions for Lua.

I can now use EmmyLua with IntelliJ Ultimate 2022.2.4 🎉

I think this should also fix issues #459 and #482 because I see Ty.<clinit> in the stack traces of the frozen threads. However, I am not 100% sure because deadlocks can get super complicated.

This possibly fixes issue #429 as well. However, there is no way for me to know for sure because the Pastebin of the thread dump expired.

Maybe the issue template should recommend GitHub Gist (unlimited duration by default) over https://ghostbin.com/ ?