From 1c945430bc7e88bf7eb56ccaa1cdcbb17b408532 Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Wed, 12 Feb 2020 21:46:10 +0900 Subject: [PATCH] Fix class loading deadlock in Error diagnostic classes Because of non-trivial initialization logic, Errors/ErrorsJvm/etc. are prone to class loading issues. This commit prevents them by preloading all error on plugin initialization step. --- .../kotlin/idea/PluginStartupActivity.java | 23 +++++++++++++++++++ .../idea/PluginStartupComponent.java.191 | 23 +++++++++++++++++++ .../idea/PluginStartupComponent.java.192 | 23 +++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/idea/src/org/jetbrains/kotlin/idea/PluginStartupActivity.java b/idea/src/org/jetbrains/kotlin/idea/PluginStartupActivity.java index 4f8ab49dadd..2b9d50ddc33 100644 --- a/idea/src/org/jetbrains/kotlin/idea/PluginStartupActivity.java +++ b/idea/src/org/jetbrains/kotlin/idea/PluginStartupActivity.java @@ -32,8 +32,13 @@ import com.intellij.openapi.util.Disposer; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.search.searches.IndexPatternSearch; import org.jetbrains.annotations.NotNull; +import org.jetbrains.kotlin.diagnostics.DiagnosticFactory; +import org.jetbrains.kotlin.diagnostics.Errors; import org.jetbrains.kotlin.idea.reporter.KotlinReportSubmitter; import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinTodoSearcher; +import org.jetbrains.kotlin.js.resolve.diagnostics.ErrorsJs; +import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm; +import org.jetbrains.kotlin.resolve.konan.diagnostics.ErrorsNative; import org.jetbrains.kotlin.utils.PathUtil; import static org.jetbrains.kotlin.idea.TestResourceBundleKt.registerAdditionalResourceBundleInTests; @@ -50,6 +55,7 @@ public class PluginStartupActivity implements StartupActivity.DumbAware { } registerPathVariable(); + initializeDiagnostics(); try { // API added in 15.0.2 @@ -88,6 +94,23 @@ public class PluginStartupActivity implements StartupActivity.DumbAware { }); } + /* + Concurrent access to Errors may lead to the class loading dead lock because of non-trivial initialization in Errors. + As a work-around, all Error classes are initialized beforehand. + It doesn't matter what exact diagnostic factories are used here. + */ + private static void initializeDiagnostics() { + consumeFactory(Errors.DEPRECATION); + consumeFactory(ErrorsJvm.ACCIDENTAL_OVERRIDE); + consumeFactory(ErrorsJs.CALL_FROM_UMD_MUST_BE_JS_MODULE_AND_JS_NON_MODULE); + consumeFactory(ErrorsNative.INCOMPATIBLE_THROWS_INHERITED); + } + + private static void consumeFactory(DiagnosticFactory factory) { + //noinspection ResultOfMethodCallIgnored + factory.getClass(); + } + private static void registerPathVariable() { PathMacros macros = PathMacros.getInstance(); macros.setMacro(KOTLIN_BUNDLED, PathUtil.getKotlinPathsForIdeaPlugin().getHomePath().getPath()); diff --git a/idea/src/org/jetbrains/kotlin/idea/PluginStartupComponent.java.191 b/idea/src/org/jetbrains/kotlin/idea/PluginStartupComponent.java.191 index 1f51bfad486..b7379d8f51f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/PluginStartupComponent.java.191 +++ b/idea/src/org/jetbrains/kotlin/idea/PluginStartupComponent.java.191 @@ -29,8 +29,13 @@ import com.intellij.openapi.updateSettings.impl.UpdateChecker; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.search.searches.IndexPatternSearch; import org.jetbrains.annotations.NotNull; +import org.jetbrains.kotlin.diagnostics.DiagnosticFactory; +import org.jetbrains.kotlin.diagnostics.Errors; import org.jetbrains.kotlin.idea.reporter.KotlinReportSubmitter; import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinTodoSearcher; +import org.jetbrains.kotlin.js.resolve.diagnostics.ErrorsJs; +import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm; +import org.jetbrains.kotlin.resolve.konan.diagnostics.ErrorsNative; import org.jetbrains.kotlin.utils.PathUtil; import java.io.File; @@ -60,6 +65,7 @@ public class PluginStartupComponent implements BaseComponent { } registerPathVariable(); + initializeDiagnostics(); try { // API added in 15.0.2 @@ -89,6 +95,23 @@ public class PluginStartupComponent implements BaseComponent { //KotlinSdkType.Companion.setUpIfNeeded(); } + /* + Concurrent access to Errors may lead to the class loading dead lock because of non-trivial initialization in Errors. + As a work-around, all Error classes are initialized beforehand. + It doesn't matter what exact diagnostic factories are used here. + */ + private static void initializeDiagnostics() { + consumeFactory(Errors.DEPRECATION); + consumeFactory(ErrorsJvm.ACCIDENTAL_OVERRIDE); + consumeFactory(ErrorsJs.CALL_FROM_UMD_MUST_BE_JS_MODULE_AND_JS_NON_MODULE); + consumeFactory(ErrorsNative.INCOMPATIBLE_THROWS_INHERITED); + } + + private static void consumeFactory(DiagnosticFactory factory) { + //noinspection ResultOfMethodCallIgnored + factory.getClass(); + } + private static void registerPathVariable() { PathMacros macros = PathMacros.getInstance(); macros.setMacro(KOTLIN_BUNDLED, PathUtil.getKotlinPathsForIdeaPlugin().getHomePath().getPath()); diff --git a/idea/src/org/jetbrains/kotlin/idea/PluginStartupComponent.java.192 b/idea/src/org/jetbrains/kotlin/idea/PluginStartupComponent.java.192 index 1f51bfad486..b7379d8f51f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/PluginStartupComponent.java.192 +++ b/idea/src/org/jetbrains/kotlin/idea/PluginStartupComponent.java.192 @@ -29,8 +29,13 @@ import com.intellij.openapi.updateSettings.impl.UpdateChecker; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.search.searches.IndexPatternSearch; import org.jetbrains.annotations.NotNull; +import org.jetbrains.kotlin.diagnostics.DiagnosticFactory; +import org.jetbrains.kotlin.diagnostics.Errors; import org.jetbrains.kotlin.idea.reporter.KotlinReportSubmitter; import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinTodoSearcher; +import org.jetbrains.kotlin.js.resolve.diagnostics.ErrorsJs; +import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm; +import org.jetbrains.kotlin.resolve.konan.diagnostics.ErrorsNative; import org.jetbrains.kotlin.utils.PathUtil; import java.io.File; @@ -60,6 +65,7 @@ public class PluginStartupComponent implements BaseComponent { } registerPathVariable(); + initializeDiagnostics(); try { // API added in 15.0.2 @@ -89,6 +95,23 @@ public class PluginStartupComponent implements BaseComponent { //KotlinSdkType.Companion.setUpIfNeeded(); } + /* + Concurrent access to Errors may lead to the class loading dead lock because of non-trivial initialization in Errors. + As a work-around, all Error classes are initialized beforehand. + It doesn't matter what exact diagnostic factories are used here. + */ + private static void initializeDiagnostics() { + consumeFactory(Errors.DEPRECATION); + consumeFactory(ErrorsJvm.ACCIDENTAL_OVERRIDE); + consumeFactory(ErrorsJs.CALL_FROM_UMD_MUST_BE_JS_MODULE_AND_JS_NON_MODULE); + consumeFactory(ErrorsNative.INCOMPATIBLE_THROWS_INHERITED); + } + + private static void consumeFactory(DiagnosticFactory factory) { + //noinspection ResultOfMethodCallIgnored + factory.getClass(); + } + private static void registerPathVariable() { PathMacros macros = PathMacros.getInstance(); macros.setMacro(KOTLIN_BUNDLED, PathUtil.getKotlinPathsForIdeaPlugin().getHomePath().getPath());