Refactor PackageCodegen and ClassBuilderOnDemand

Make ClassBuilderOnDemand non-abstract and create its instance directly in
PackageCodegen's constructor
This commit is contained in:
Alexander Udalov
2014-05-23 19:10:02 +04:00
parent 4ee7d2e72a
commit 9dd81bdb3d
3 changed files with 40 additions and 68 deletions
@@ -16,49 +16,30 @@
package org.jetbrains.jet.codegen; package org.jetbrains.jet.codegen;
import com.google.common.collect.Lists; import kotlin.Function0;
import org.jetbrains.annotations.NotNull; 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> classBuilder;
public abstract class ClassBuilderOnDemand { public ClassBuilderOnDemand(@NotNull Function0<ClassBuilder> createClassBuilder) {
this.classBuilder = LockBasedStorageManager.NO_LOCKS.createLazyValue(createClassBuilder);
private ClassBuilder classBuilder;
private final List<ClassBuilderCallback> 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);
}
} }
@NotNull @NotNull
public ClassBuilder getClassBuilder() { public ClassBuilder getClassBuilder() {
if (classBuilder == null) { return classBuilder.invoke();
classBuilder = createClassBuilder();
for (ClassBuilderCallback callback : optionalDeclarations) {
callback.doSomething(classBuilder);
}
}
return classBuilder;
} }
public void done() { public void done() {
if (classBuilder != null) { if (isActivated()) {
classBuilder.done(); classBuilder.invoke().done();
} }
} }
public boolean isActivated() { public boolean isActivated() {
return classBuilder != null; return classBuilder.isComputed();
} }
} }
@@ -35,9 +35,6 @@ import org.jetbrains.org.objectweb.asm.Type;
import java.io.File; import java.io.File;
import java.util.*; 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 { public class ClassFileFactory implements OutputFileCollection {
private final GenerationState state; private final GenerationState state;
private final ClassBuilderFactory builderFactory; private final ClassBuilderFactory builderFactory;
@@ -57,7 +54,7 @@ public class ClassFileFactory implements OutputFileCollection {
} }
@NotNull @NotNull
private ClassBuilder newVisitor(@NotNull Type asmType, @NotNull Collection<? extends PsiFile> sourceFiles) { public ClassBuilder newVisitor(@NotNull Type asmType, @NotNull Collection<? extends PsiFile> sourceFiles) {
String outputFilePath = asmType.getInternalName() + ".class"; String outputFilePath = asmType.getInternalName() + ".class";
state.getProgress().reportOutput(toIoFilesIgnoringNonPhysical(sourceFiles), new File(outputFilePath)); state.getProgress().reportOutput(toIoFilesIgnoringNonPhysical(sourceFiles), new File(outputFilePath));
ClassBuilder answer = builderFactory.newClassBuilder(); ClassBuilder answer = builderFactory.newClassBuilder();
@@ -106,18 +103,11 @@ public class ClassFileFactory implements OutputFileCollection {
} }
@NotNull @NotNull
public PackageCodegen forPackage(@NotNull final FqName fqName, @NotNull final Collection<JetFile> files) { public PackageCodegen forPackage(@NotNull FqName fqName, @NotNull Collection<JetFile> files) {
assert !isDone : "Already done!"; assert !isDone : "Already done!";
PackageCodegen codegen = package2codegen.get(fqName); PackageCodegen codegen = package2codegen.get(fqName);
if (codegen == null) { if (codegen == null) {
ClassBuilderOnDemand onDemand = new ClassBuilderOnDemand() { codegen = new PackageCodegen(state, files, fqName);
@NotNull
@Override
protected ClassBuilder createClassBuilder() {
return newVisitor(asmTypeByFqNameWithoutInnerClasses(getPackageClassFqName(fqName)), files);
}
};
codegen = new PackageCodegen(onDemand, fqName, state, files);
package2codegen.put(fqName, codegen); package2codegen.put(fqName, codegen);
} }
@@ -22,10 +22,10 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.util.ArrayUtil; import com.intellij.util.ArrayUtil;
import com.intellij.util.PathUtil; import com.intellij.util.PathUtil;
import com.intellij.util.SmartList; import com.intellij.util.SmartList;
import kotlin.Function0;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.codegen.context.CodegenContext; import org.jetbrains.jet.codegen.context.CodegenContext;
@@ -74,28 +74,27 @@ public class PackageCodegen {
private final Collection<JetFile> files; private final Collection<JetFile> files;
private final PackageFragmentDescriptor packageFragment; private final PackageFragmentDescriptor packageFragment;
private final PackageFragmentDescriptor compiledPackageFragment; private final PackageFragmentDescriptor compiledPackageFragment;
private final List<DeserializedCallableMemberDescriptor> previouslyCompiledCallables;
public PackageCodegen( public PackageCodegen(@NotNull GenerationState state, @NotNull Collection<JetFile> files, @NotNull final FqName fqName) {
@NotNull ClassBuilderOnDemand v,
@NotNull final FqName fqName,
@NotNull GenerationState state,
@NotNull Collection<JetFile> packageFiles
) {
this.state = state; this.state = state;
this.v = v; this.files = files;
this.files = packageFiles;
this.packageFragment = getOnlyPackageFragment(); this.packageFragment = getOnlyPackageFragment();
this.compiledPackageFragment = getCompiledPackageFragment(); this.compiledPackageFragment = getCompiledPackageFragment(packageFragment);
this.previouslyCompiledCallables = filterDeserializedCallables(compiledPackageFragment);
final PsiFile sourceFile = packageFiles.size() == 1 && getPreviouslyCompiledCallables().isEmpty() this.v = new ClassBuilderOnDemand(new Function0<ClassBuilder>() {
? packageFiles.iterator().next().getContainingFile() : null;
v.addOptionalDeclaration(new ClassBuilderOnDemand.ClassBuilderCallback() {
@Override @Override
public void doSomething(@NotNull ClassBuilder v) { public ClassBuilder invoke() {
Collection<JetFile> 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, v.defineClass(sourceFile, V1_6,
ACC_PUBLIC | ACC_FINAL, ACC_PUBLIC | ACC_FINAL,
JvmClassName.byFqNameWithoutInnerClasses(getPackageClassFqName(fqName)).getInternalName(), className,
null, null,
"java/lang/Object", "java/lang/Object",
ArrayUtil.EMPTY_STRING_ARRAY ArrayUtil.EMPTY_STRING_ARRAY
@@ -104,12 +103,13 @@ public class PackageCodegen {
if (sourceFile != null) { if (sourceFile != null) {
v.visitSource(sourceFile.getName(), null); v.visitSource(sourceFile.getName(), null);
} }
return v;
} }
}); });
} }
@Nullable @Nullable
private PackageFragmentDescriptor getCompiledPackageFragment() { private static PackageFragmentDescriptor getCompiledPackageFragment(@NotNull PackageFragmentDescriptor packageFragment) {
if (!IncrementalCompilation.ENABLED) { if (!IncrementalCompilation.ENABLED) {
return null; return null;
} }
@@ -125,20 +125,21 @@ public class PackageCodegen {
} }
@NotNull @NotNull
private List<DeserializedCallableMemberDescriptor> getPreviouslyCompiledCallables() { private static List<DeserializedCallableMemberDescriptor> filterDeserializedCallables(@Nullable PackageFragmentDescriptor packageFragment) {
if (packageFragment == null) {
return Collections.emptyList();
}
List<DeserializedCallableMemberDescriptor> callables = Lists.newArrayList(); List<DeserializedCallableMemberDescriptor> callables = Lists.newArrayList();
if (compiledPackageFragment != null) { for (DeclarationDescriptor member : packageFragment.getMemberScope().getAllDescriptors()) {
for (DeclarationDescriptor member : compiledPackageFragment.getMemberScope().getAllDescriptors()) { if (member instanceof DeserializedCallableMemberDescriptor) {
if (member instanceof DeserializedCallableMemberDescriptor) { callables.add((DeserializedCallableMemberDescriptor) member);
callables.add((DeserializedCallableMemberDescriptor) member);
}
} }
} }
return callables; return callables;
} }
private void generateDelegationsToPreviouslyCompiled(Map<CallableMemberDescriptor, Runnable> generateCallableMemberTasks) { private void generateDelegationsToPreviouslyCompiled(@NotNull Map<CallableMemberDescriptor, Runnable> generateCallableMemberTasks) {
for (final DeserializedCallableMemberDescriptor member : getPreviouslyCompiledCallables()) { for (final DeserializedCallableMemberDescriptor member : previouslyCompiledCallables) {
generateCallableMemberTasks.put(member, new Runnable() { generateCallableMemberTasks.put(member, new Runnable() {
@Override @Override
public void run() { public void run() {