diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassFileFactory.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassFileFactory.java index d8b25d258c3..7c23abec485 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassFileFactory.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ClassFileFactory.java @@ -20,9 +20,12 @@ import com.google.common.collect.Lists; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; import com.intellij.util.Function; +import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.io.DataOutputStream; import kotlin.collections.CollectionsKt; +import kotlin.collections.MapsKt; +import kotlin.jvm.functions.Function0; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; @@ -49,12 +52,13 @@ import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.getMappingFileName; public class ClassFileFactory implements OutputFileCollection { private final GenerationState state; private final ClassBuilderFactory builderFactory; - private final Map package2codegen = new HashMap(); - private final Map multifileClass2codegen = new HashMap(); private final Map generators = new LinkedHashMap(); private boolean isDone = false; + private final Set packagePartSourceFiles = new HashSet(); + private final Map partsGroupedByPackage = new LinkedHashMap(); + public ClassFileFactory(@NotNull GenerationState state, @NotNull ClassBuilderFactory builderFactory) { this.state = state; this.builderFactory = builderFactory; @@ -84,37 +88,23 @@ public class ClassFileFactory implements OutputFileCollection { void done() { if (!isDone) { isDone = true; - Collection packageCodegens = package2codegen.values(); - Collection multifileClassCodegens = multifileClass2codegen.values(); - writeModuleMappings(packageCodegens, multifileClassCodegens); + writeModuleMappings(); } } - private void writeModuleMappings( - @NotNull Collection packageCodegens, - @NotNull Collection multifileClassCodegens - ) { + private void writeModuleMappings() { final JvmPackageTable.PackageTable.Builder builder = JvmPackageTable.PackageTable.newBuilder(); String outputFilePath = getMappingFileName(state.getModuleName()); - List parts = collectGeneratedPackageParts(packageCodegens, multifileClassCodegens); - - Set sourceFiles = new HashSet(); - // TODO extract common logic - for (PackageCodegen codegen : packageCodegens) { - sourceFiles.addAll(toIoFilesIgnoringNonPhysical(PackagePartClassUtils.getFilesWithCallables(codegen.getFiles()))); - } - for (MultifileClassCodegen codegen : multifileClassCodegens) { - sourceFiles.addAll(toIoFilesIgnoringNonPhysical(PackagePartClassUtils.getFilesWithCallables(codegen.getFiles()))); - } + List parts = new SmartList(partsGroupedByPackage.values()); for (PackageParts part : ClassFileUtilsKt.addCompiledPartsAndSort(parts, state)) { PackageParts.Companion.serialize(part, builder); } if (builder.getPackagePartsCount() != 0) { - state.getProgress().reportOutput(sourceFiles, new File(outputFilePath)); - generators.put(outputFilePath, new OutAndSourceFileList(CollectionsKt.toList(sourceFiles)) { + state.getProgress().reportOutput(packagePartSourceFiles, new File(outputFilePath)); + generators.put(outputFilePath, new OutAndSourceFileList(CollectionsKt.toList(packagePartSourceFiles)) { @Override public byte[] asBytes(ClassBuilderFactory factory) { try { @@ -150,34 +140,6 @@ public class ClassFileFactory implements OutputFileCollection { } } - private static List collectGeneratedPackageParts( - @NotNull Collection packageCodegens, - @NotNull Collection multifileClassCodegens - ) { - Map mergedPartsByPackageName = new LinkedHashMap(); - - for (PackageCodegen packageCodegen : packageCodegens) { - PackageParts generatedParts = packageCodegen.getPackageParts(); - PackageParts premergedParts = new PackageParts(generatedParts.getPackageFqName()); - mergedPartsByPackageName.put(generatedParts.getPackageFqName(), premergedParts); - premergedParts.getParts().addAll(generatedParts.getParts()); - } - - for (MultifileClassCodegen multifileClassCodegen : multifileClassCodegens) { - PackageParts multifileClassParts = multifileClassCodegen.getPackageParts(); - PackageParts premergedParts = mergedPartsByPackageName.get(multifileClassParts.getPackageFqName()); - if (premergedParts == null) { - premergedParts = new PackageParts(multifileClassParts.getPackageFqName()); - mergedPartsByPackageName.put(multifileClassParts.getPackageFqName(), premergedParts); - } - premergedParts.getParts().addAll(multifileClassParts.getParts()); - } - - List result = new ArrayList(); - result.addAll(mergedPartsByPackageName.values()); - return result; - } - @NotNull @Override public List asList() { @@ -222,24 +184,34 @@ public class ClassFileFactory implements OutputFileCollection { @NotNull public PackageCodegen forPackage(@NotNull FqName fqName, @NotNull Collection files) { assert !isDone : "Already done!"; - PackageCodegen codegen = package2codegen.get(fqName); - if (codegen == null) { - codegen = new PackageCodegen(state, files, fqName); - package2codegen.put(fqName, codegen); - } - - return codegen; + registerPackagePartSourceFiles(files); + return new PackageCodegen(state, files, fqName, buildNewPackagePartRegistry(fqName)); } @NotNull public MultifileClassCodegen forMultifileClass(@NotNull FqName facadeFqName, @NotNull Collection files) { assert !isDone : "Already done!"; - MultifileClassCodegen codegen = multifileClass2codegen.get(facadeFqName); - if (codegen == null) { - codegen = new MultifileClassCodegen(state, files, facadeFqName); - multifileClass2codegen.put(facadeFqName, codegen); - } - return codegen; + registerPackagePartSourceFiles(files); + return new MultifileClassCodegen(state, files, facadeFqName, buildNewPackagePartRegistry(facadeFqName.parent())); + } + + private PackagePartRegistry buildNewPackagePartRegistry(@NotNull FqName packageFqName) { + final String packageFqNameAsString = packageFqName.asString(); + return new PackagePartRegistry() { + @Override + public void addPart(@NotNull String partShortName) { + MapsKt.getOrPut(partsGroupedByPackage, packageFqNameAsString, new Function0() { + @Override + public PackageParts invoke() { + return new PackageParts(packageFqNameAsString); + } + }).getParts().add(partShortName); + } + }; + } + + public void registerPackagePartSourceFiles(Collection files) { + packagePartSourceFiles.addAll(toIoFilesIgnoringNonPhysical(PackagePartClassUtils.getFilesWithCallables(files))); } @NotNull diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassCodegen.kt index ea693af69c8..f7d863502bc 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/MultifileClassCodegen.kt @@ -58,7 +58,8 @@ import java.util.* class MultifileClassCodegen( private val state: GenerationState, val files: Collection, - private val facadeFqName: FqName + private val facadeFqName: FqName, + private val packagePartRegistry: PackagePartRegistry ) { private val facadeClassType = AsmUtil.asmTypeByFqNameWithoutInnerClasses(facadeFqName) @@ -75,8 +76,6 @@ class MultifileClassCodegen( private fun getDeserializedCallables(compiledPackageFragment: PackageFragmentDescriptor) = compiledPackageFragment.getMemberScope().getContributedDescriptors(DescriptorKindFilter.CALLABLES, MemberScope.ALL_NAME_FILTER).filterIsInstance() - val packageParts = PackageParts(facadeFqName.parent().asString()) - private val classBuilder = ClassBuilderOnDemand { val originFile = files.firstOrNull() val actualPackageFragment = packageFragment ?: @@ -202,7 +201,7 @@ class MultifileClassCodegen( partFqNames.add(partClassInfo.fileClassFqName) val name = partType.internalName - packageParts.parts.add(name.substring(name.lastIndexOf('/') + 1)) + packagePartRegistry.addPart(name.substring(name.lastIndexOf('/') + 1)) val builder = state.factory.newVisitor(MultifileClassPart(file, packageFragment, facadeFqName), partType, file) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegen.java index cd961ac6446..ca49f941c8b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegen.java @@ -41,17 +41,18 @@ public class PackageCodegen { private final GenerationState state; private final Collection files; private final PackageFragmentDescriptor packageFragment; - private final PackageParts packageParts; + private final PackagePartRegistry packagePartRegistry; public PackageCodegen( @NotNull GenerationState state, @NotNull Collection files, - @NotNull FqName packageFqName + @NotNull FqName packageFqName, + @NotNull PackagePartRegistry registry ) { this.state = state; this.files = files; this.packageFragment = getOnlyPackageFragment(packageFqName); - packageParts = new PackageParts(packageFqName.asString()); + packagePartRegistry = registry; } public void generate(@NotNull CompilationErrorHandler errorHandler) { @@ -110,7 +111,7 @@ public class PackageCodegen { if (!generatePackagePart || !state.getGenerateDeclaredClassFilter().shouldGeneratePackagePart(file)) return null; String name = fileClassType.getInternalName(); - packageParts.getParts().add(name.substring(name.lastIndexOf('/') + 1)); + packagePartRegistry.addPart(name.substring(name.lastIndexOf('/') + 1)); ClassBuilder builder = state.getFactory().newVisitor(JvmDeclarationOriginKt.PackagePart(file, packageFragment), fileClassType, file); @@ -147,10 +148,6 @@ public class PackageCodegen { MemberCodegen.genClassOrObject(packagePartContext, classOrObject, state, null); } - public PackageParts getPackageParts() { - return packageParts; - } - public Collection getFiles() { return files; } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackagePartRegistry.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackagePartRegistry.kt new file mode 100644 index 00000000000..0b157191270 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackagePartRegistry.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2010-2016 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.kotlin.codegen + +interface PackagePartRegistry { + fun addPart(partShortName: String) +}