diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClassBuilderOnDemand.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClassBuilderOnDemand.java index c99c82831b2..87a1f1c3adb 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClassBuilderOnDemand.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClassBuilderOnDemand.java @@ -16,49 +16,30 @@ package org.jetbrains.jet.codegen; -import com.google.common.collect.Lists; +import kotlin.Function0; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.storage.LockBasedStorageManager; +import org.jetbrains.jet.storage.NotNullLazyValue; -import java.util.List; +public class ClassBuilderOnDemand { + private final NotNullLazyValue classBuilder; -public abstract class ClassBuilderOnDemand { - - private ClassBuilder classBuilder; - - private final List optionalDeclarations = Lists.newArrayList(); - - interface ClassBuilderCallback { - void doSomething(@NotNull ClassBuilder classBuilder); - } - - @NotNull - protected abstract ClassBuilder createClassBuilder(); - - public void addOptionalDeclaration(@NotNull ClassBuilderCallback callback) { - optionalDeclarations.add(callback); - if (classBuilder != null) { - callback.doSomething(classBuilder); - } + public ClassBuilderOnDemand(@NotNull Function0 createClassBuilder) { + this.classBuilder = LockBasedStorageManager.NO_LOCKS.createLazyValue(createClassBuilder); } @NotNull public ClassBuilder getClassBuilder() { - if (classBuilder == null) { - classBuilder = createClassBuilder(); - for (ClassBuilderCallback callback : optionalDeclarations) { - callback.doSomething(classBuilder); - } - } - return classBuilder; + return classBuilder.invoke(); } public void done() { - if (classBuilder != null) { - classBuilder.done(); + if (isActivated()) { + classBuilder.invoke().done(); } } public boolean isActivated() { - return classBuilder != null; + return classBuilder.isComputed(); } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClassFileFactory.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClassFileFactory.java index a8b6204022e..a750e241b61 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClassFileFactory.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClassFileFactory.java @@ -35,9 +35,6 @@ import org.jetbrains.org.objectweb.asm.Type; import java.io.File; import java.util.*; -import static org.jetbrains.jet.codegen.AsmUtil.asmTypeByFqNameWithoutInnerClasses; -import static org.jetbrains.jet.lang.resolve.java.PackageClassUtils.getPackageClassFqName; - public class ClassFileFactory implements OutputFileCollection { private final GenerationState state; private final ClassBuilderFactory builderFactory; @@ -57,7 +54,7 @@ public class ClassFileFactory implements OutputFileCollection { } @NotNull - private ClassBuilder newVisitor(@NotNull Type asmType, @NotNull Collection sourceFiles) { + public ClassBuilder newVisitor(@NotNull Type asmType, @NotNull Collection sourceFiles) { String outputFilePath = asmType.getInternalName() + ".class"; state.getProgress().reportOutput(toIoFilesIgnoringNonPhysical(sourceFiles), new File(outputFilePath)); ClassBuilder answer = builderFactory.newClassBuilder(); @@ -106,18 +103,11 @@ public class ClassFileFactory implements OutputFileCollection { } @NotNull - public PackageCodegen forPackage(@NotNull final FqName fqName, @NotNull final Collection files) { + public PackageCodegen forPackage(@NotNull FqName fqName, @NotNull Collection files) { assert !isDone : "Already done!"; PackageCodegen codegen = package2codegen.get(fqName); if (codegen == null) { - ClassBuilderOnDemand onDemand = new ClassBuilderOnDemand() { - @NotNull - @Override - protected ClassBuilder createClassBuilder() { - return newVisitor(asmTypeByFqNameWithoutInnerClasses(getPackageClassFqName(fqName)), files); - } - }; - codegen = new PackageCodegen(onDemand, fqName, state, files); + codegen = new PackageCodegen(state, files, fqName); package2codegen.put(fqName, codegen); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/PackageCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/PackageCodegen.java index 174ea3a6c4e..4fec035d0d0 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/PackageCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/PackageCodegen.java @@ -22,10 +22,10 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiFile; import com.intellij.util.ArrayUtil; import com.intellij.util.PathUtil; import com.intellij.util.SmartList; +import kotlin.Function0; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.codegen.context.CodegenContext; @@ -74,28 +74,27 @@ public class PackageCodegen { private final Collection files; private final PackageFragmentDescriptor packageFragment; private final PackageFragmentDescriptor compiledPackageFragment; + private final List previouslyCompiledCallables; - public PackageCodegen( - @NotNull ClassBuilderOnDemand v, - @NotNull final FqName fqName, - @NotNull GenerationState state, - @NotNull Collection packageFiles - ) { + public PackageCodegen(@NotNull GenerationState state, @NotNull Collection files, @NotNull final FqName fqName) { this.state = state; - this.v = v; - this.files = packageFiles; + this.files = files; this.packageFragment = getOnlyPackageFragment(); - this.compiledPackageFragment = getCompiledPackageFragment(); + this.compiledPackageFragment = getCompiledPackageFragment(packageFragment); + this.previouslyCompiledCallables = filterDeserializedCallables(compiledPackageFragment); - final PsiFile sourceFile = packageFiles.size() == 1 && getPreviouslyCompiledCallables().isEmpty() - ? packageFiles.iterator().next().getContainingFile() : null; - - v.addOptionalDeclaration(new ClassBuilderOnDemand.ClassBuilderCallback() { + this.v = new ClassBuilderOnDemand(new Function0() { @Override - public void doSomething(@NotNull ClassBuilder v) { + public ClassBuilder invoke() { + Collection files = PackageCodegen.this.files; + JetFile sourceFile = files.size() == 1 && previouslyCompiledCallables.isEmpty() + ? files.iterator().next() : null; + + String className = JvmClassName.byFqNameWithoutInnerClasses(getPackageClassFqName(fqName)).getInternalName(); + ClassBuilder v = PackageCodegen.this.state.getFactory().newVisitor(Type.getObjectType(className), files); v.defineClass(sourceFile, V1_6, ACC_PUBLIC | ACC_FINAL, - JvmClassName.byFqNameWithoutInnerClasses(getPackageClassFqName(fqName)).getInternalName(), + className, null, "java/lang/Object", ArrayUtil.EMPTY_STRING_ARRAY @@ -104,12 +103,13 @@ public class PackageCodegen { if (sourceFile != null) { v.visitSource(sourceFile.getName(), null); } + return v; } }); } @Nullable - private PackageFragmentDescriptor getCompiledPackageFragment() { + private static PackageFragmentDescriptor getCompiledPackageFragment(@NotNull PackageFragmentDescriptor packageFragment) { if (!IncrementalCompilation.ENABLED) { return null; } @@ -125,20 +125,21 @@ public class PackageCodegen { } @NotNull - private List getPreviouslyCompiledCallables() { + private static List filterDeserializedCallables(@Nullable PackageFragmentDescriptor packageFragment) { + if (packageFragment == null) { + return Collections.emptyList(); + } List callables = Lists.newArrayList(); - if (compiledPackageFragment != null) { - for (DeclarationDescriptor member : compiledPackageFragment.getMemberScope().getAllDescriptors()) { - if (member instanceof DeserializedCallableMemberDescriptor) { - callables.add((DeserializedCallableMemberDescriptor) member); - } + for (DeclarationDescriptor member : packageFragment.getMemberScope().getAllDescriptors()) { + if (member instanceof DeserializedCallableMemberDescriptor) { + callables.add((DeserializedCallableMemberDescriptor) member); } } return callables; } - private void generateDelegationsToPreviouslyCompiled(Map generateCallableMemberTasks) { - for (final DeserializedCallableMemberDescriptor member : getPreviouslyCompiledCallables()) { + private void generateDelegationsToPreviouslyCompiled(@NotNull Map generateCallableMemberTasks) { + for (final DeserializedCallableMemberDescriptor member : previouslyCompiledCallables) { generateCallableMemberTasks.put(member, new Runnable() { @Override public void run() {