From d647d2abbcf946e167bd6756df0e90f6f7380a67 Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Wed, 19 Feb 2014 17:52:06 +0400 Subject: [PATCH] Move caching of kotlin binaries classes to application level Fix code in DecompiledUtils --- .../jvm/compiler/CliVirtualFileFinder.java | 5 ++- .../cli/jvm/compiler/JetCoreEnvironment.java | 2 + .../kotlin/KotlinBinaryClassCache.java | 45 +++++++++++++++++++ .../kotlin/VirtualFileKotlinClassFinder.java | 23 +--------- .../resolve/kotlin/KotlinClassFinder.java | 6 --- idea/src/META-INF/plugin.xml | 3 ++ .../caches/JetFromJavaDescriptorHelper.java | 3 +- .../libraries/DecompiledDataFactory.java | 4 +- .../jet/plugin/libraries/DecompiledUtils.java | 36 +++------------ .../libraries/JetClassFileDecompiler.java | 2 +- .../plugin/libraries/JetClsStubBuilder.java | 2 +- .../vfilefinder/KotlinClassFileIndex.java | 5 +-- 12 files changed, 68 insertions(+), 68 deletions(-) create mode 100644 compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/kotlin/KotlinBinaryClassCache.java diff --git a/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/CliVirtualFileFinder.java b/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/CliVirtualFileFinder.java index 01cad805fd7..10e009ac92b 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/CliVirtualFileFinder.java +++ b/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/CliVirtualFileFinder.java @@ -19,6 +19,7 @@ package org.jetbrains.jet.cli.jvm.compiler; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.resolve.kotlin.KotlinBinaryClassCache; import org.jetbrains.jet.lang.resolve.kotlin.VirtualFileFinder; import org.jetbrains.jet.lang.resolve.kotlin.VirtualFileKotlinClassFinder; import org.jetbrains.jet.lang.resolve.name.FqName; @@ -44,10 +45,10 @@ public class CliVirtualFileFinder extends VirtualFileKotlinClassFinder implement return null; } - private VirtualFile findKotlinFile(@NotNull FqName className, @NotNull VirtualFile root) { + private static VirtualFile findKotlinFile(@NotNull FqName className, @NotNull VirtualFile root) { VirtualFile vFile = findFileInRoot(className.asString(), root, '.'); //NOTE: currently we use VirtualFileFinder to find Kotlin binaries only - if (vFile != null && createKotlinClass(vFile).getClassHeader() != null) { + if (vFile != null && KotlinBinaryClassCache.getKotlinBinaryClass(vFile).getClassHeader() != null) { return vFile; } return null; diff --git a/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/JetCoreEnvironment.java b/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/JetCoreEnvironment.java index a0b447897e3..7c56aec9da1 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/JetCoreEnvironment.java +++ b/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/JetCoreEnvironment.java @@ -55,6 +55,7 @@ import org.jetbrains.jet.lang.parsing.JetParserDefinition; import org.jetbrains.jet.lang.parsing.JetScriptDefinitionProvider; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.resolve.java.JetFilesProvider; +import org.jetbrains.jet.lang.resolve.kotlin.KotlinBinaryClassCache; import org.jetbrains.jet.lang.resolve.kotlin.VirtualFileFinder; import org.jetbrains.jet.plugin.JetFileType; import org.jetbrains.jet.utils.PathUtil; @@ -144,6 +145,7 @@ public class JetCoreEnvironment { applicationEnvironment.registerParserDefinition(new JetParserDefinition()); applicationEnvironment.getApplication().registerService(OperationModeProvider.class, new CompilerModeProvider()); + applicationEnvironment.getApplication().registerService(KotlinBinaryClassCache.class, new KotlinBinaryClassCache()); return applicationEnvironment; } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/kotlin/KotlinBinaryClassCache.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/kotlin/KotlinBinaryClassCache.java new file mode 100644 index 00000000000..1ae81df195b --- /dev/null +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/kotlin/KotlinBinaryClassCache.java @@ -0,0 +1,45 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.lang.resolve.kotlin; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.containers.SLRUCache; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.storage.LockBasedStorageManager; + +public final class KotlinBinaryClassCache { + + // This cache must be small: we only query the same file a few times in a row (from different places) + // Since it is on application level we should be careful about this cache. Consider profiling multiple projects indexing simultaneously. + private final SLRUCache cache = new SLRUCache(2, 2) { + @NotNull + @Override + public KotlinJvmBinaryClass createValue(VirtualFile virtualFile) { + // Operations under this lock are not supposed to involve other locks + return new VirtualFileKotlinClass(new LockBasedStorageManager(), virtualFile); + } + }; + + @NotNull + public static KotlinJvmBinaryClass getKotlinBinaryClass(@NotNull VirtualFile file) { + KotlinBinaryClassCache service = ServiceManager.getService(KotlinBinaryClassCache.class); + synchronized (service.cache) { + return service.cache.get(file); + } + } +} diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/kotlin/VirtualFileKotlinClassFinder.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/kotlin/VirtualFileKotlinClassFinder.java index 067d21ff532..af0b0b33336 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/kotlin/VirtualFileKotlinClassFinder.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/kotlin/VirtualFileKotlinClassFinder.java @@ -17,36 +17,15 @@ package org.jetbrains.jet.lang.resolve.kotlin; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.containers.SLRUCache; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.resolve.name.FqName; -import org.jetbrains.jet.storage.LockBasedStorageManager; public abstract class VirtualFileKotlinClassFinder implements VirtualFileFinder { - - // This cache must be small: we only query the same file a few times in a row (from different places) - private final SLRUCache cache = new SLRUCache(2, 2) { - @NotNull - @Override - public KotlinJvmBinaryClass createValue(VirtualFile virtualFile) { - // Operations under this lock are not supposed to involve other locks - return new VirtualFileKotlinClass(new LockBasedStorageManager(), virtualFile); - } - }; - @Nullable @Override public KotlinJvmBinaryClass findKotlinClass(@NotNull FqName fqName) { VirtualFile file = findVirtualFileWithHeader(fqName); - return file == null ? null : createKotlinClass(file); - } - - @Override - @NotNull - public KotlinJvmBinaryClass createKotlinClass(@NotNull VirtualFile file) { - synchronized (cache) { - return cache.get(file); - } + return file == null ? null : KotlinBinaryClassCache.getKotlinBinaryClass(file); } } diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/KotlinClassFinder.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/KotlinClassFinder.java index ee196357431..6331b5b7120 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/KotlinClassFinder.java +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/KotlinClassFinder.java @@ -16,9 +16,6 @@ package org.jetbrains.jet.lang.resolve.kotlin; -import com.intellij.openapi.components.ServiceManager; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.resolve.name.FqName; @@ -27,7 +24,4 @@ public interface KotlinClassFinder { @Nullable KotlinJvmBinaryClass findKotlinClass(@NotNull FqName fqName); - - @NotNull - KotlinJvmBinaryClass createKotlinClass(@NotNull VirtualFile virtualFile); } diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 613085ada95..ec1f920c6f3 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -105,6 +105,9 @@ + + diff --git a/idea/src/org/jetbrains/jet/plugin/caches/JetFromJavaDescriptorHelper.java b/idea/src/org/jetbrains/jet/plugin/caches/JetFromJavaDescriptorHelper.java index a0e332cb3a8..5bbcd784825 100644 --- a/idea/src/org/jetbrains/jet/plugin/caches/JetFromJavaDescriptorHelper.java +++ b/idea/src/org/jetbrains/jet/plugin/caches/JetFromJavaDescriptorHelper.java @@ -27,6 +27,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.descriptors.serialization.*; import org.jetbrains.jet.lang.descriptors.ClassKind; import org.jetbrains.jet.lang.resolve.java.JavaResolverPsiUtils; +import org.jetbrains.jet.lang.resolve.kotlin.KotlinBinaryClassCache; import org.jetbrains.jet.lang.resolve.kotlin.KotlinJvmBinaryClass; import org.jetbrains.jet.lang.resolve.kotlin.VirtualFileFinder; import org.jetbrains.jet.lang.resolve.kotlin.header.KotlinClassHeader; @@ -111,7 +112,7 @@ public class JetFromJavaDescriptorHelper { private static String[] getAnnotationDataForKotlinClass(@NotNull PsiClass psiClass) { VirtualFile virtualFile = getVirtualFileForPsiClass(psiClass); if (virtualFile != null) { - KotlinJvmBinaryClass kotlinClass = VirtualFileFinder.SERVICE.getInstance(psiClass.getProject()).createKotlinClass(virtualFile); + KotlinJvmBinaryClass kotlinClass = KotlinBinaryClassCache.getKotlinBinaryClass(virtualFile); KotlinClassHeader header = kotlinClass.getClassHeader(); if (header != null) { return header.getAnnotationData(); diff --git a/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledDataFactory.java b/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledDataFactory.java index c9b5d19e4d4..2376050a052 100644 --- a/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledDataFactory.java +++ b/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledDataFactory.java @@ -28,8 +28,8 @@ import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.resolve.BindingTraceContext; import org.jetbrains.jet.lang.resolve.MemberComparator; import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver; +import org.jetbrains.jet.lang.resolve.kotlin.KotlinBinaryClassCache; import org.jetbrains.jet.lang.resolve.kotlin.KotlinJvmBinaryClass; -import org.jetbrains.jet.lang.resolve.kotlin.VirtualFileFinder; import org.jetbrains.jet.lang.resolve.kotlin.header.KotlinClassHeader; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.renderer.DescriptorRenderer; @@ -66,7 +66,7 @@ public final class DecompiledDataFactory { InjectorForJavaDescriptorResolver injector = InjectorForJavaDescriptorResolverUtil.create(project, new BindingTraceContext()); this.javaDescriptorResolver = injector.getJavaDescriptorResolver(); - KotlinJvmBinaryClass kotlinClass = VirtualFileFinder.SERVICE.getInstance(project).createKotlinClass(classFile); + KotlinJvmBinaryClass kotlinClass = KotlinBinaryClassCache.getKotlinBinaryClass(classFile); this.classFqName = kotlinClass.getClassName().getFqNameForClassNameWithoutDollars(); KotlinClassHeader header = kotlinClass.getClassHeader(); diff --git a/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledUtils.java b/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledUtils.java index b290a64c1f1..572cbba470f 100644 --- a/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledUtils.java +++ b/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledUtils.java @@ -21,47 +21,23 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.resolve.java.PackageClassUtils; -import org.jetbrains.jet.lang.resolve.kotlin.VirtualFileKotlinClass; +import org.jetbrains.jet.lang.resolve.kotlin.KotlinBinaryClassCache; import org.jetbrains.jet.lang.resolve.kotlin.header.KotlinClassHeader; -import org.jetbrains.jet.storage.LockBasedStorageManager; public final class DecompiledUtils { - private static final String PACKAGE_FRAGMENT_SIGNATURE = PackageClassUtils.PACKAGE_CLASS_NAME_SUFFIX + "-"; public static boolean isKotlinCompiledFile(@NotNull VirtualFile file) { if (!StdFileTypes.CLASS.getDefaultExtension().equals(file.getExtension())) { return false; } - return isKotlinInternalClass(file) || checkFile(file); + KotlinClassHeader header = KotlinBinaryClassCache.getKotlinBinaryClass(file).getClassHeader(); + return header != null; } - public static boolean isKotlinInternalClass(@NotNull VirtualFile file) { - // FIXME: not sure if this is a good heuristic - String name = file.getName(); - int pos = name.indexOf('$'); - if (pos > 0) { - name = name.substring(0, pos) + ".class"; - VirtualFile supposedHost = file.getParent().findChild(name); - if (supposedHost != null) { - return checkFile(supposedHost); - } - } - - if (name.contains(PACKAGE_FRAGMENT_SIGNATURE)) { - KotlinClassHeader header = new VirtualFileKotlinClass(LockBasedStorageManager.NO_LOCKS, file).getClassHeader(); - if (header != null && header.getKind() == KotlinClassHeader.Kind.PACKAGE_FRAGMENT) { - return true; - } - } - - return false; - } - - private static boolean checkFile(@NotNull VirtualFile file) { - KotlinClassHeader header = new VirtualFileKotlinClass(LockBasedStorageManager.NO_LOCKS, file).getClassHeader(); - return header != null && header.getAnnotationData() != null; + public static boolean isKotlinInternalCompiledFile(@NotNull VirtualFile file) { + KotlinClassHeader header = KotlinBinaryClassCache.getKotlinBinaryClass(file).getClassHeader(); + return header != null && header.getKind() == KotlinClassHeader.Kind.PACKAGE_FRAGMENT; } public static CharSequence decompile(@NotNull VirtualFile file) { diff --git a/idea/src/org/jetbrains/jet/plugin/libraries/JetClassFileDecompiler.java b/idea/src/org/jetbrains/jet/plugin/libraries/JetClassFileDecompiler.java index ae69f559de2..e28dce3de13 100644 --- a/idea/src/org/jetbrains/jet/plugin/libraries/JetClassFileDecompiler.java +++ b/idea/src/org/jetbrains/jet/plugin/libraries/JetClassFileDecompiler.java @@ -40,6 +40,6 @@ public class JetClassFileDecompiler extends ClassFileDecompilers.Full { @NotNull @Override public FileViewProvider createFileViewProvider(@NotNull VirtualFile file, @NotNull PsiManager manager, boolean physical) { - return new JetClassFileViewProvider(manager, file, physical, DecompiledUtils.isKotlinInternalClass(file)); + return new JetClassFileViewProvider(manager, file, physical, DecompiledUtils.isKotlinInternalCompiledFile(file)); } } diff --git a/idea/src/org/jetbrains/jet/plugin/libraries/JetClsStubBuilder.java b/idea/src/org/jetbrains/jet/plugin/libraries/JetClsStubBuilder.java index 848707ab28c..c387c7ac312 100644 --- a/idea/src/org/jetbrains/jet/plugin/libraries/JetClsStubBuilder.java +++ b/idea/src/org/jetbrains/jet/plugin/libraries/JetClsStubBuilder.java @@ -37,7 +37,7 @@ public class JetClsStubBuilder extends ClsStubBuilder { public PsiFileStub buildFileStub(@NotNull FileContent content) throws ClsFormatException { VirtualFile file = content.getFile(); - if (DecompiledUtils.isKotlinInternalClass(file)) { + if (DecompiledUtils.isKotlinInternalCompiledFile(file)) { return null; } diff --git a/idea/src/org/jetbrains/jet/plugin/vfilefinder/KotlinClassFileIndex.java b/idea/src/org/jetbrains/jet/plugin/vfilefinder/KotlinClassFileIndex.java index 388cd1e8dda..2650bd5f850 100644 --- a/idea/src/org/jetbrains/jet/plugin/vfilefinder/KotlinClassFileIndex.java +++ b/idea/src/org/jetbrains/jet/plugin/vfilefinder/KotlinClassFileIndex.java @@ -22,8 +22,8 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.indexing.*; import com.intellij.util.io.KeyDescriptor; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.resolve.kotlin.KotlinBinaryClassCache; import org.jetbrains.jet.lang.resolve.kotlin.KotlinJvmBinaryClass; -import org.jetbrains.jet.lang.resolve.kotlin.VirtualFileFinder; import org.jetbrains.jet.lang.resolve.kotlin.header.KotlinClassHeader; import org.jetbrains.jet.lang.resolve.name.FqName; @@ -75,8 +75,7 @@ public final class KotlinClassFileIndex extends ScalarIndexExtension { @Override public Map map(FileContent inputData) { try { - KotlinJvmBinaryClass kotlinClass = VirtualFileFinder.SERVICE.getInstance(inputData.getProject()) - .createKotlinClass(inputData.getFile()); + KotlinJvmBinaryClass kotlinClass = KotlinBinaryClassCache.getKotlinBinaryClass(inputData.getFile()); KotlinClassHeader header = kotlinClass.getClassHeader(); if (header != null && header.getKind() != KotlinClassHeader.Kind.INCOMPATIBLE_ABI_VERSION) { return Collections.singletonMap(kotlinClass.getClassName().getFqNameForClassNameWithoutDollars(), null);