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 3938f25e895..fad9f3d1591 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,8 +19,8 @@ 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.*; -import org.jetbrains.jet.lang.resolve.kotlin.header.KotlinClassHeader; +import org.jetbrains.jet.lang.resolve.kotlin.VirtualFileFinder; +import org.jetbrains.jet.lang.resolve.kotlin.VirtualFileKotlinClassFinder; import org.jetbrains.jet.lang.resolve.name.FqName; public class CliVirtualFileFinder extends VirtualFileKotlinClassFinder implements VirtualFileFinder { @@ -70,7 +70,7 @@ public class CliVirtualFileFinder extends VirtualFileKotlinClassFinder implement return null; } //NOTE: currently we use VirtualFileFinder to find Kotlin binaries only - if (KotlinClassHeader.read(createKotlinClass(vFile)) != null) { + if (createKotlinClass(vFile).getClassHeader() != null) { return vFile; } } 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 0d36523d3da..71f36e40ab2 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 @@ -16,7 +16,9 @@ package org.jetbrains.jet.lang.resolve.kotlin; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.vfs.VirtualFile; +import jet.Function0; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.asm4.ClassReader; @@ -24,7 +26,11 @@ import org.jetbrains.asm4.ClassVisitor; import org.jetbrains.asm4.FieldVisitor; import org.jetbrains.asm4.MethodVisitor; import org.jetbrains.jet.lang.resolve.java.JvmClassName; +import org.jetbrains.jet.lang.resolve.kotlin.header.KotlinClassHeader; 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.ExceptionUtils; import java.io.IOException; @@ -34,10 +40,27 @@ import static org.jetbrains.asm4.Opcodes.ASM4; public class VirtualFileKotlinClass implements KotlinJvmBinaryClass { private final VirtualFile file; - private JvmClassName className; + private final NotNullLazyValue className; + private final NullableLazyValue classHeader; - public VirtualFileKotlinClass(@NotNull VirtualFile file) { + public VirtualFileKotlinClass(@NotNull StorageManager storageManager, @NotNull VirtualFile file) { this.file = file; + this.className = storageManager.createLazyValue( + new Function0() { + @Override + public JvmClassName invoke() { + return computeClassName(); + } + } + ); + this.classHeader = storageManager.createNullableLazyValue( + new Function0() { + @Override + public KotlinClassHeader invoke() { + return KotlinClassHeader.read(VirtualFileKotlinClass.this); + } + } + ); } @NotNull @@ -45,24 +68,32 @@ public class VirtualFileKotlinClass implements KotlinJvmBinaryClass { return file; } + @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 (IOException e) { + throw ExceptionUtils.rethrow(e); + } + return classNameRef.get(); + } + @NotNull @Override public JvmClassName getClassName() { - if (className == null) { - 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) { - className = JvmClassName.byInternalName(name); - } - }, SKIP_CODE | SKIP_DEBUG | SKIP_FRAMES); - } - catch (IOException e) { - throw ExceptionUtils.rethrow(e); - } - } + return className.invoke(); + } - return className; + @Override + public KotlinClassHeader getClassHeader() { + return classHeader.invoke(); } @Override 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 72bdc7b031f..cd4161337d6 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 @@ -21,6 +21,7 @@ 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 { @@ -29,7 +30,8 @@ public abstract class VirtualFileKotlinClassFinder implements VirtualFileFinder @NotNull @Override public KotlinJvmBinaryClass createValue(VirtualFile virtualFile) { - return new VirtualFileKotlinClass(virtualFile); + // Operations under this lock are not supposed to involve other locks + return new VirtualFileKotlinClass(new LockBasedStorageManager(), virtualFile); } }; 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 e4800211936..ce479da6823 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 @@ -113,7 +113,7 @@ public final class DeserializedDescriptorResolver { @Nullable private String[] readData(@NotNull KotlinJvmBinaryClass kotlinClass, @NotNull SerializedDataHeader.Kind expectedKind) { - KotlinClassHeader header = KotlinClassHeader.read(kotlinClass); + KotlinClassHeader header = kotlinClass.getClassHeader(); if (header instanceof SerializedDataHeader) { SerializedDataHeader serializedDataHeader = (SerializedDataHeader) header; if (serializedDataHeader.getKind() != expectedKind) return null; 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 e0c74ea4973..8a581965057 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 @@ -19,6 +19,7 @@ package org.jetbrains.jet.lang.resolve.kotlin; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.resolve.java.JvmClassName; +import org.jetbrains.jet.lang.resolve.kotlin.header.KotlinClassHeader; import org.jetbrains.jet.lang.resolve.name.Name; public interface KotlinJvmBinaryClass { @@ -29,6 +30,9 @@ public interface KotlinJvmBinaryClass { void loadMemberAnnotations(@NotNull MemberVisitor visitor); + @Nullable + KotlinClassHeader getClassHeader(); + interface MemberVisitor { // TODO: abstract signatures for methods and fields instead of ASM 'desc' strings? diff --git a/idea/src/org/jetbrains/jet/plugin/caches/JetFromJavaDescriptorHelper.java b/idea/src/org/jetbrains/jet/plugin/caches/JetFromJavaDescriptorHelper.java index 47ac4f5c0f4..088f1781043 100644 --- a/idea/src/org/jetbrains/jet/plugin/caches/JetFromJavaDescriptorHelper.java +++ b/idea/src/org/jetbrains/jet/plugin/caches/JetFromJavaDescriptorHelper.java @@ -31,7 +31,6 @@ import org.jetbrains.jet.lang.descriptors.ClassKind; import org.jetbrains.jet.lang.resolve.java.JavaResolverPsiUtils; import org.jetbrains.jet.lang.resolve.kotlin.KotlinClassFinder; import org.jetbrains.jet.lang.resolve.kotlin.KotlinJvmBinaryClass; -import org.jetbrains.jet.lang.resolve.kotlin.VirtualFileKotlinClass; import org.jetbrains.jet.lang.resolve.kotlin.header.KotlinClassHeader; import org.jetbrains.jet.lang.resolve.kotlin.header.SerializedDataHeader; import org.jetbrains.jet.lang.resolve.name.FqName; @@ -120,7 +119,7 @@ public class JetFromJavaDescriptorHelper { VirtualFile virtualFile = getVirtualFileForPsiClass(psiClass); if (virtualFile != null) { KotlinJvmBinaryClass kotlinClass = KotlinClassFinder.SERVICE.getInstance(psiClass.getProject()).createKotlinClass(virtualFile); - KotlinClassHeader header = KotlinClassHeader.read(kotlinClass); + KotlinClassHeader header = kotlinClass.getClassHeader(); if (header instanceof SerializedDataHeader) { return ((SerializedDataHeader) 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 a7fce506432..50a5cf90a43 100644 --- a/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledDataFactory.java +++ b/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledDataFactory.java @@ -71,7 +71,7 @@ public final class DecompiledDataFactory { KotlinJvmBinaryClass kotlinClass = KotlinClassFinder.SERVICE.getInstance(project).createKotlinClass(classFile); this.classFqName = kotlinClass.getClassName().getFqNameForClassNameWithoutDollars(); - KotlinClassHeader header = KotlinClassHeader.read(kotlinClass); + KotlinClassHeader header = kotlinClass.getClassHeader(); assert header instanceof SerializedDataHeader : "Decompiled data factory shouldn't be called on an unsupported file: " + classFile; this.classFileHeader = (SerializedDataHeader) header; } diff --git a/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledUtils.java b/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledUtils.java index 9b599973439..aef570997f8 100644 --- a/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledUtils.java +++ b/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledUtils.java @@ -22,7 +22,6 @@ import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.resolve.kotlin.KotlinClassFinder; import org.jetbrains.jet.lang.resolve.kotlin.KotlinJvmBinaryClass; -import org.jetbrains.jet.lang.resolve.kotlin.header.KotlinClassHeader; import org.jetbrains.jet.lang.resolve.kotlin.header.SerializedDataHeader; public final class DecompiledUtils { @@ -33,7 +32,7 @@ public final class DecompiledUtils { } //TODO: check index KotlinJvmBinaryClass kotlinClass = KotlinClassFinder.SERVICE.getInstance(project).createKotlinClass(file); - return KotlinClassHeader.read(kotlinClass) instanceof SerializedDataHeader; + return kotlinClass.getClassHeader() instanceof SerializedDataHeader; } private DecompiledUtils() { diff --git a/idea/src/org/jetbrains/jet/plugin/stubindex/builder/EmptyPackageFragmentClsStubBuilderFactory.java b/idea/src/org/jetbrains/jet/plugin/stubindex/builder/EmptyPackageFragmentClsStubBuilderFactory.java index f9f4fc72eb3..371e23bda01 100644 --- a/idea/src/org/jetbrains/jet/plugin/stubindex/builder/EmptyPackageFragmentClsStubBuilderFactory.java +++ b/idea/src/org/jetbrains/jet/plugin/stubindex/builder/EmptyPackageFragmentClsStubBuilderFactory.java @@ -27,8 +27,8 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.resolve.java.PackageClassUtils; import org.jetbrains.jet.lang.resolve.kotlin.KotlinJvmBinaryClass; import org.jetbrains.jet.lang.resolve.kotlin.VirtualFileKotlinClass; -import org.jetbrains.jet.lang.resolve.kotlin.header.KotlinClassHeader; import org.jetbrains.jet.lang.resolve.kotlin.header.PackageFragmentClassHeader; +import org.jetbrains.jet.storage.LockBasedStorageManager; /** * This class is needed to build an empty PSI stub for compiled package fragment classes. This results in these classes not showing up @@ -46,8 +46,8 @@ public class EmptyPackageFragmentClsStubBuilderFactory extends ClsStubBuilderFac public boolean canBeProcessed(VirtualFile file, byte[] bytes) { if (file.getName().contains(PackageClassUtils.PACKAGE_CLASS_NAME_SUFFIX + "-") && StdFileTypes.CLASS.getDefaultExtension().equals(file.getExtension())) { - KotlinJvmBinaryClass kotlinClass = new VirtualFileKotlinClass(file); - return KotlinClassHeader.read(kotlinClass) instanceof PackageFragmentClassHeader; + KotlinJvmBinaryClass kotlinClass = new VirtualFileKotlinClass(LockBasedStorageManager.NO_LOCKS, file); + return kotlinClass.getClassHeader() instanceof PackageFragmentClassHeader; } return false; } diff --git a/idea/src/org/jetbrains/jet/plugin/vfilefinder/KotlinClassFileIndex.java b/idea/src/org/jetbrains/jet/plugin/vfilefinder/KotlinClassFileIndex.java index 110e7f6aff0..4771934e264 100644 --- a/idea/src/org/jetbrains/jet/plugin/vfilefinder/KotlinClassFileIndex.java +++ b/idea/src/org/jetbrains/jet/plugin/vfilefinder/KotlinClassFileIndex.java @@ -78,7 +78,7 @@ public final class KotlinClassFileIndex extends ScalarIndexExtension { try { KotlinJvmBinaryClass kotlinClass = KotlinClassFinder.SERVICE.getInstance(inputData.getProject()) .createKotlinClass(inputData.getFile()); - KotlinClassHeader header = KotlinClassHeader.read(kotlinClass); + KotlinClassHeader header = kotlinClass.getClassHeader(); if (header != null && !(header instanceof IncompatibleAnnotationHeader)) { return Collections.singletonMap(kotlinClass.getClassName().getFqNameForClassNameWithoutDollars(), null); }