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 10e009ac92b..3c1f36a719a 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 @@ -37,23 +37,15 @@ public class CliVirtualFileFinder extends VirtualFileKotlinClassFinder implement @Override public VirtualFile findVirtualFileWithHeader(@NotNull FqName className) { for (VirtualFile root : classPath) { - VirtualFile fileInRoot = findKotlinFile(className, root); - if (fileInRoot != null) { + VirtualFile fileInRoot = findFileInRoot(className.asString(), root, '.'); + //NOTE: currently we use VirtualFileFinder to find Kotlin binaries only + if (fileInRoot != null && KotlinBinaryClassCache.getKotlinBinaryClass(fileInRoot) != null) { return fileInRoot; } } return null; } - 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 && KotlinBinaryClassCache.getKotlinBinaryClass(vFile).getClassHeader() != null) { - return vFile; - } - return null; - } - @Override public VirtualFile findVirtualFile(@NotNull String internalName) { for (VirtualFile root : classPath) { 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 index 1ae81df195b..85410d24291 100644 --- 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 @@ -17,29 +17,29 @@ package org.jetbrains.jet.lang.resolve.kotlin; import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.SLRUCache; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.storage.LockBasedStorageManager; +import org.jetbrains.annotations.Nullable; 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) { + 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); + public Ref createValue(VirtualFile virtualFile) { + return Ref.create(VirtualFileKotlinClass.create(virtualFile)); } }; - @NotNull + @Nullable public static KotlinJvmBinaryClass getKotlinBinaryClass(@NotNull VirtualFile file) { KotlinBinaryClassCache service = ServiceManager.getService(KotlinBinaryClassCache.class); synchronized (service.cache) { - return service.cache.get(file); + return service.cache.get(file).get(); } } } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/kotlin/VirtualFileKotlinClass.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/kotlin/VirtualFileKotlinClass.java index ba9767e052e..d325a16bf29 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/kotlin/VirtualFileKotlinClass.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/kotlin/VirtualFileKotlinClass.java @@ -19,7 +19,6 @@ package org.jetbrains.jet.lang.resolve.kotlin; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Ref; import com.intellij.openapi.vfs.VirtualFile; -import kotlin.Function0; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.asm4.ClassReader; @@ -30,9 +29,6 @@ import org.jetbrains.jet.lang.resolve.java.JvmClassName; import org.jetbrains.jet.lang.resolve.kotlin.header.KotlinClassHeader; import org.jetbrains.jet.lang.resolve.kotlin.header.ReadKotlinClassHeaderAnnotationVisitor; import org.jetbrains.jet.lang.resolve.name.Name; -import org.jetbrains.jet.storage.NotNullLazyValue; -import org.jetbrains.jet.storage.NullableLazyValue; -import org.jetbrains.jet.storage.StorageManager; import org.jetbrains.jet.utils.UtilsPackage; import static org.jetbrains.asm4.ClassReader.*; @@ -42,27 +38,49 @@ public class VirtualFileKotlinClass implements KotlinJvmBinaryClass { private final static Logger LOG = Logger.getInstance(VirtualFileKotlinClass.class); private final VirtualFile file; - private final NotNullLazyValue className; - private final NullableLazyValue classHeader; + private final JvmClassName className; + private final KotlinClassHeader classHeader; - public VirtualFileKotlinClass(@NotNull StorageManager storageManager, @NotNull VirtualFile file) { + private VirtualFileKotlinClass(@NotNull VirtualFile file, @NotNull JvmClassName className, @NotNull KotlinClassHeader classHeader) { this.file = file; - this.className = storageManager.createLazyValue( - new Function0() { - @Override - public JvmClassName invoke() { - return computeClassName(); - } + this.className = className; + this.classHeader = classHeader; + } + + @Nullable + /* package */ static VirtualFileKotlinClass create(@NotNull VirtualFile file) { + try { + final ReadKotlinClassHeaderAnnotationVisitor readHeaderVisitor = new ReadKotlinClassHeaderAnnotationVisitor(); + final Ref classNameRef = Ref.create(); + new ClassReader(file.contentsToByteArray()).accept(new ClassVisitor(ASM4) { + @Override + public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { + classNameRef.set(JvmClassName.byInternalName(name)); } - ); - this.classHeader = storageManager.createNullableLazyValue( - new Function0() { - @Override - public KotlinClassHeader invoke() { - return ReadKotlinClassHeaderAnnotationVisitor.read(VirtualFileKotlinClass.this); - } + + @Override + public org.jetbrains.asm4.AnnotationVisitor visitAnnotation(String desc, boolean visible) { + return convertAnnotationVisitor(readHeaderVisitor, desc); } - ); + + @Override + public void visitEnd() { + readHeaderVisitor.visitEnd(); + } + }, SKIP_CODE | SKIP_DEBUG | SKIP_FRAMES); + + JvmClassName className = classNameRef.get(); + if (className == null) return null; + + KotlinClassHeader header = readHeaderVisitor.createHeader(); + if (header == null) return null; + + return new VirtualFileKotlinClass(file, className, header); + } + catch (Throwable e) { + LOG.warn(renderFileReadingErrorMessage(file), e); + return null; + } } @NotNull @@ -71,32 +89,15 @@ public class VirtualFileKotlinClass implements KotlinJvmBinaryClass { } @NotNull - private JvmClassName computeClassName() { - final Ref classNameRef = Ref.create(); - try { - new ClassReader(file.contentsToByteArray()).accept(new ClassVisitor(ASM4) { - @Override - public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { - classNameRef.set(JvmClassName.byInternalName(name)); - } - }, SKIP_CODE | SKIP_DEBUG | SKIP_FRAMES); - } - catch (Throwable e) { - logFileReadingError(e); - throw UtilsPackage.rethrow(e); - } - return classNameRef.get(); + @Override + public JvmClassName getClassName() { + return className; } @NotNull - @Override - public JvmClassName getClassName() { - return className.invoke(); - } - @Override public KotlinClassHeader getClassHeader() { - return classHeader.invoke(); + return classHeader; } @Override @@ -115,7 +116,7 @@ public class VirtualFileKotlinClass implements KotlinJvmBinaryClass { }, SKIP_CODE | SKIP_DEBUG | SKIP_FRAMES); } catch (Throwable e) { - logFileReadingError(e); + LOG.error(renderFileReadingErrorMessage(file), e); throw UtilsPackage.rethrow(e); } } @@ -200,7 +201,7 @@ public class VirtualFileKotlinClass implements KotlinJvmBinaryClass { }, SKIP_CODE | SKIP_DEBUG | SKIP_FRAMES); } catch (Throwable e) { - logFileReadingError(e); + LOG.error(renderFileReadingErrorMessage(file), e); throw UtilsPackage.rethrow(e); } } @@ -211,6 +212,13 @@ public class VirtualFileKotlinClass implements KotlinJvmBinaryClass { return JvmClassName.byInternalName(desc.substring(1, desc.length() - 1)); } + @NotNull + private static String renderFileReadingErrorMessage(@NotNull VirtualFile file) { + return "Could not read file: " + file.getPath() + "\n" + + "Size in bytes: " + file.getLength() + "\n" + + "File type: " + file.getFileType().getName(); + } + @Override public int hashCode() { return file.hashCode(); @@ -225,13 +233,4 @@ public class VirtualFileKotlinClass implements KotlinJvmBinaryClass { public String toString() { return getClass().getSimpleName() + ": " + file.toString(); } - - private void logFileReadingError(@NotNull Throwable e) { - LOG.error( - "Could not read file: " + file.getPath() + "\n" - + "Size in bytes: " + file.getLength() + "\n" - + "File type: " + file.getFileType().getName(), - e - ); - } } diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/resolvers.kt b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/resolvers.kt index d4a9f076c4b..29e98e7b423 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/resolvers.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/lazy/resolvers.kt @@ -75,8 +75,8 @@ fun LazyJavaResolverContext.findClassInJava(fqName: FqName): JavaClassLookupResu } val kotlinClass = kotlinClassFinder.findKotlinClass(fqName) - val header = kotlinClass?.getClassHeader() - if (kotlinClass != null && header != null) { + if (kotlinClass != null) { + val header = kotlinClass.getClassHeader() if (header.kind == KotlinClassHeader.Kind.CLASS) { val descriptor = packageFragmentProvider.resolveKotlinBinaryClass(kotlinClass) if (descriptor != null) { diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/DeserializedDescriptorResolver.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/DeserializedDescriptorResolver.java index 46e4067071b..89899079dde 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/DeserializedDescriptorResolver.java +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/DeserializedDescriptorResolver.java @@ -117,8 +117,6 @@ public final class DeserializedDescriptorResolver { @Nullable private String[] readData(@NotNull KotlinJvmBinaryClass kotlinClass, @NotNull KotlinClassHeader.Kind expectedKind) { KotlinClassHeader header = kotlinClass.getClassHeader(); - if (header == null) return null; - if (header.getKind() == KotlinClassHeader.Kind.INCOMPATIBLE_ABI_VERSION) { errorReporter.reportIncompatibleAbiVersion(kotlinClass, header.getVersion()); } diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/KotlinJvmBinaryClass.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/KotlinJvmBinaryClass.java index c2992d60f16..53ed0a031ce 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/KotlinJvmBinaryClass.java +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/KotlinJvmBinaryClass.java @@ -30,7 +30,7 @@ public interface KotlinJvmBinaryClass { void visitMembers(@NotNull MemberVisitor visitor); - @Nullable + @NotNull KotlinClassHeader getClassHeader(); interface MemberVisitor { diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/header/ReadKotlinClassHeaderAnnotationVisitor.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/header/ReadKotlinClassHeaderAnnotationVisitor.java index 6d1ff71f11e..1de3b4c7558 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/header/ReadKotlinClassHeaderAnnotationVisitor.java +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/header/ReadKotlinClassHeaderAnnotationVisitor.java @@ -20,7 +20,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.resolve.java.AbiVersionUtil; import org.jetbrains.jet.lang.resolve.java.JvmClassName; -import org.jetbrains.jet.lang.resolve.kotlin.KotlinJvmBinaryClass; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.Name; @@ -53,16 +52,6 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor private KotlinClassHeader.Kind headerKind = null; private KotlinSyntheticClass.Kind syntheticClassKind = null; - private ReadKotlinClassHeaderAnnotationVisitor() { - } - - @Nullable - public static KotlinClassHeader read(@NotNull KotlinJvmBinaryClass kotlinClass) { - ReadKotlinClassHeaderAnnotationVisitor visitor = new ReadKotlinClassHeaderAnnotationVisitor(); - kotlinClass.loadClassAnnotations(visitor); - return visitor.createHeader(); - } - @Nullable public KotlinClassHeader createHeader() { if (headerKind == null) { diff --git a/idea/src/org/jetbrains/jet/plugin/caches/JetFromJavaDescriptorHelper.java b/idea/src/org/jetbrains/jet/plugin/caches/JetFromJavaDescriptorHelper.java index 5bbcd784825..d23d4a2a49f 100644 --- a/idea/src/org/jetbrains/jet/plugin/caches/JetFromJavaDescriptorHelper.java +++ b/idea/src/org/jetbrains/jet/plugin/caches/JetFromJavaDescriptorHelper.java @@ -29,8 +29,6 @@ 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; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.Name; @@ -113,9 +111,8 @@ public class JetFromJavaDescriptorHelper { VirtualFile virtualFile = getVirtualFileForPsiClass(psiClass); if (virtualFile != null) { KotlinJvmBinaryClass kotlinClass = KotlinBinaryClassCache.getKotlinBinaryClass(virtualFile); - KotlinClassHeader header = kotlinClass.getClassHeader(); - if (header != null) { - return header.getAnnotationData(); + if (kotlinClass != null) { + return kotlinClass.getClassHeader().getAnnotationData(); } } return null; diff --git a/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledTextFactory.kt b/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledTextFactory.kt index 5fdab8b7c12..9a263e295b3 100644 --- a/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledTextFactory.kt +++ b/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledTextFactory.kt @@ -35,10 +35,9 @@ public fun buildDecompiledText( resolver: ResolverForDecompiler = DeserializerForDecompiler(classFile) ): DecompiledText { val kotlinClass = KotlinBinaryClassCache.getKotlinBinaryClass(classFile) - val classFqName = kotlinClass.getClassName().getFqNameForClassNameWithoutDollars() - val classFileHeader = kotlinClass.getClassHeader() - assert(classFileHeader != null) { "Decompiled data factory shouldn't be called on an unsupported file: " + classFile } - val kind = classFileHeader!!.kind + assert(kotlinClass != null) { "Decompiled data factory shouldn't be called on an unsupported file: " + classFile } + val classFqName = kotlinClass!!.getClassName().getFqNameForClassNameWithoutDollars() + val kind = kotlinClass.getClassHeader().kind val packageFqName = classFqName.parent() return if (kind == KotlinClassHeader.Kind.PACKAGE_FACADE) { diff --git a/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledUtils.kt b/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledUtils.kt index 1126410aa9a..64d92ef70fe 100644 --- a/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledUtils.kt +++ b/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledUtils.kt @@ -30,7 +30,7 @@ public fun isKotlinCompiledFile(file: VirtualFile): Boolean { if (isKotlinCompiledFileWithIncompatibleAbiVersion(file)) { return false } - val header = KotlinBinaryClassCache.getKotlinBinaryClass(file).getClassHeader() + val header = KotlinBinaryClassCache.getKotlinBinaryClass(file)?.getClassHeader() return header != null && header.syntheticClassKind != KotlinSyntheticClass.Kind.TRAIT_IMPL } @@ -38,7 +38,7 @@ public fun isKotlinCompiledFileWithIncompatibleAbiVersion(file: VirtualFile): Bo if (file.getExtension() != StdFileTypes.CLASS.getDefaultExtension()) { return false } - val header = KotlinBinaryClassCache.getKotlinBinaryClass(file).getClassHeader() + val header = KotlinBinaryClassCache.getKotlinBinaryClass(file)?.getClassHeader() return header?.kind == KotlinClassHeader.Kind.INCOMPATIBLE_ABI_VERSION } @@ -49,6 +49,6 @@ public fun isKotlinInternalCompiledFile(file: VirtualFile): Boolean { if (ClassFileViewProvider.isInnerClass(file)) { return true } - val header = KotlinBinaryClassCache.getKotlinBinaryClass(file).getClassHeader() + val header = KotlinBinaryClassCache.getKotlinBinaryClass(file)?.getClassHeader() return header?.kind == KotlinClassHeader.Kind.SYNTHETIC_CLASS } diff --git a/idea/src/org/jetbrains/jet/plugin/libraries/DeserializerForDecompiler.kt b/idea/src/org/jetbrains/jet/plugin/libraries/DeserializerForDecompiler.kt index 74b1dc14025..8457cebb259 100644 --- a/idea/src/org/jetbrains/jet/plugin/libraries/DeserializerForDecompiler.kt +++ b/idea/src/org/jetbrains/jet/plugin/libraries/DeserializerForDecompiler.kt @@ -46,7 +46,8 @@ import org.jetbrains.jet.lang.resolve.kotlin.ConstantDescriptorDeserializer public fun DeserializerForDecompiler(classFile: VirtualFile): DeserializerForDecompiler { val kotlinClass = KotlinBinaryClassCache.getKotlinBinaryClass(classFile) - val classFqName = kotlinClass.getClassName().getFqNameForClassNameWithoutDollars() + assert(kotlinClass != null) { "Decompiled data factory shouldn't be called on an unsupported file: " + classFile } + val classFqName = kotlinClass!!.getClassName().getFqNameForClassNameWithoutDollars() val packageFqName = classFqName.parent() return DeserializerForDecompiler(classFile.getParent()!!, packageFqName) } @@ -174,7 +175,7 @@ public class DeserializerForDecompiler(val packageDirectory: VirtualFile, val di } private fun deserializeBinaryClass(kotlinClass: KotlinJvmBinaryClass): ClassDescriptor { - val data = kotlinClass.getClassHeader()?.annotationData + val data = kotlinClass.getClassHeader().annotationData if (data == null) { LOG.error("Annotation data missing for ${kotlinClass.getClassName()}") } diff --git a/idea/src/org/jetbrains/jet/plugin/vfilefinder/KotlinClassFileIndex.java b/idea/src/org/jetbrains/jet/plugin/vfilefinder/KotlinClassFileIndex.java index 2650bd5f850..6cc42ad89df 100644 --- a/idea/src/org/jetbrains/jet/plugin/vfilefinder/KotlinClassFileIndex.java +++ b/idea/src/org/jetbrains/jet/plugin/vfilefinder/KotlinClassFileIndex.java @@ -76,8 +76,7 @@ public final class KotlinClassFileIndex extends ScalarIndexExtension { public Map map(FileContent inputData) { try { KotlinJvmBinaryClass kotlinClass = KotlinBinaryClassCache.getKotlinBinaryClass(inputData.getFile()); - KotlinClassHeader header = kotlinClass.getClassHeader(); - if (header != null && header.getKind() != KotlinClassHeader.Kind.INCOMPATIBLE_ABI_VERSION) { + if (kotlinClass != null && kotlinClass.getClassHeader().getKind() != KotlinClassHeader.Kind.INCOMPATIBLE_ABI_VERSION) { return Collections.singletonMap(kotlinClass.getClassName().getFqNameForClassNameWithoutDollars(), null); } } diff --git a/idea/tests/org/jetbrains/jet/plugin/libraries/InternalCompiledClassesTest.kt b/idea/tests/org/jetbrains/jet/plugin/libraries/InternalCompiledClassesTest.kt index d8e29ce3013..4bbb5ea26f8 100644 --- a/idea/tests/org/jetbrains/jet/plugin/libraries/InternalCompiledClassesTest.kt +++ b/idea/tests/org/jetbrains/jet/plugin/libraries/InternalCompiledClassesTest.kt @@ -79,7 +79,7 @@ public class InternalCompiledClassesTest : JetLightCodeInsightFixtureTestCase() } private fun isSyntheticClassOfKind(kind: KotlinSyntheticClass.Kind) : VirtualFile.() -> Boolean = { - val header = KotlinBinaryClassCache.getKotlinBinaryClass(this).getClassHeader() + val header = KotlinBinaryClassCache.getKotlinBinaryClass(this)?.getClassHeader() header?.syntheticClassKind == kind }