Store .kotlin_module files in MetadataSerializer

Compilation of top level functions/properties/typealiases results in a bunch of
different .kotlin_metadata files, so we need to store names of these files to
avoid scanning the file system in the compiler when loading code compiled by
K2MetadataCompiler.

For this, we reuse the PackageTable protobuf message, which is already used for
exactly the same purpose in the JVM back-end
This commit is contained in:
Alexander Udalov
2016-11-14 12:31:00 +03:00
parent 1d71c19b42
commit 32792c5ce4
8 changed files with 1215 additions and 74 deletions
@@ -19,9 +19,7 @@ package org.jetbrains.kotlin.codegen;
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;
@@ -31,7 +29,6 @@ import org.jetbrains.annotations.TestOnly;
import org.jetbrains.kotlin.backend.common.output.OutputFile;
import org.jetbrains.kotlin.backend.common.output.OutputFileCollection;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.load.kotlin.JvmMetadataVersion;
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils;
import org.jetbrains.kotlin.load.kotlin.PackageParts;
import org.jetbrains.kotlin.name.FqName;
@@ -40,9 +37,7 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
import org.jetbrains.kotlin.serialization.jvm.JvmPackageTable;
import org.jetbrains.org.objectweb.asm.Type;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.*;
@@ -100,47 +95,28 @@ public class ClassFileFactory implements OutputFileCollection {
final JvmPackageTable.PackageTable.Builder builder = JvmPackageTable.PackageTable.newBuilder();
String outputFilePath = getMappingFileName(state.getModuleName());
List<PackageParts> parts = new SmartList<PackageParts>(partsGroupedByPackage.values());
for (PackageParts part : ClassFileUtilsKt.addCompiledPartsAndSort(parts, state)) {
PackageParts.Companion.serialize(part, builder);
for (PackageParts part : ClassFileUtilsKt.addCompiledPartsAndSort(partsGroupedByPackage.values(), state)) {
part.addTo(builder);
}
if (builder.getPackagePartsCount() != 0) {
generators.put(outputFilePath, new OutAndSourceFileList(CollectionsKt.toList(packagePartSourceFiles)) {
@Override
public byte[] asBytes(ClassBuilderFactory factory) {
try {
ByteArrayOutputStream moduleMapping = new ByteArrayOutputStream(4096);
DataOutputStream dataOutStream = new DataOutputStream(moduleMapping);
int[] version = JvmMetadataVersion.INSTANCE.toArray();
dataOutStream.writeInt(version.length);
for (int number : version) {
dataOutStream.writeInt(number);
}
builder.build().writeTo(dataOutStream);
dataOutStream.flush();
return moduleMapping.toByteArray();
}
catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
if (builder.getPackagePartsCount() == 0) return;
@Override
public String asText(ClassBuilderFactory factory) {
try {
return new String(asBytes(factory), "UTF-8");
}
catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
generators.put(outputFilePath, new OutAndSourceFileList(CollectionsKt.toList(packagePartSourceFiles)) {
@Override
public byte[] asBytes(ClassBuilderFactory factory) {
return ClassFileUtilsKt.serializeToByteArray(builder);
}
@Override
public String asText(ClassBuilderFactory factory) {
try {
return new String(asBytes(factory), "UTF-8");
}
});
}
catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
});
}
@NotNull
@@ -16,10 +16,14 @@
package org.jetbrains.kotlin.codegen
import com.intellij.util.io.DataOutputStream
import org.jetbrains.kotlin.backend.common.output.OutputFile
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.load.kotlin.JvmMetadataVersion
import org.jetbrains.kotlin.load.kotlin.ModuleMapping
import org.jetbrains.kotlin.load.kotlin.PackageParts
import org.jetbrains.kotlin.serialization.jvm.JvmPackageTable
import java.io.ByteArrayOutputStream
fun ClassFileFactory.getClassFiles(): Iterable<OutputFile> {
return asList().filterClassFiles()
@@ -29,12 +33,12 @@ fun List<OutputFile>.filterClassFiles(): Iterable<OutputFile> {
return filter { it.relativePath.endsWith(".class") }
}
fun List<PackageParts>.addCompiledPartsAndSort(state: GenerationState): List<PackageParts> =
fun Iterable<PackageParts>.addCompiledPartsAndSort(state: GenerationState): List<PackageParts> =
addCompiledParts(state).sortedBy { it.packageFqName }
private fun List<PackageParts>.addCompiledParts(state: GenerationState): List<PackageParts> {
val incrementalCache = state.incrementalCacheForThisTarget ?: return this
val moduleMappingData = incrementalCache.getModuleMappingData() ?: return this
private fun Iterable<PackageParts>.addCompiledParts(state: GenerationState): List<PackageParts> {
val incrementalCache = state.incrementalCacheForThisTarget ?: return this.toList()
val moduleMappingData = incrementalCache.getModuleMappingData() ?: return this.toList()
val mapping = ModuleMapping.create(moduleMappingData, "<incremental>")
@@ -54,3 +58,16 @@ private fun List<PackageParts>.addCompiledParts(state: GenerationState): List<Pa
newPackageParts
}
}
fun JvmPackageTable.PackageTable.Builder.serializeToByteArray(): ByteArray {
val moduleMapping = ByteArrayOutputStream(4096)
val out = DataOutputStream(moduleMapping)
val version = JvmMetadataVersion.INSTANCE.toArray()
out.writeInt(version.size)
for (number in version) {
out.writeInt(number)
}
build().writeTo(out)
out.flush()
return moduleMapping.toByteArray()
}